Skip to content

The TCP server is unable to respond to connection and data reception events from the Python client #336

Description

@williamlzw

The TCP server is unable to respond to connection and data reception events from the Python client, but it can respond to client disconnection events.

using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using WatsonTcp;


namespace TcpServer
{
    internal class Program
    {
        // 和Python端完全一致的配置
        private const string SERVER_IP = "localhost";
        private const int SERVER_PORT = 5555;
        private const int HEAD_SIZE = 8; // 固定包头8字节
        private static WatsonTcpServer _tcpServer;

        static void Main(string[] args)
        {
            // 1. 创建WatsonTcp服务端实例
            _tcpServer = new WatsonTcpServer(SERVER_IP, SERVER_PORT);

            // 2. 绑定核心事件
            _tcpServer.Events.ClientConnected += TcpServer_ClientConnected;    // 客户端连接事件
            _tcpServer.Events.ClientDisconnected += TcpServer_ClientDisconnected;// 客户端断开事件
            _tcpServer.Events.MessageReceived += TcpServer_MessageReceived;    // 接收消息核心事件

            // 3. 启动服务端
            _tcpServer.Start();
            Console.WriteLine($"服务端已启动:{SERVER_IP}:{SERVER_PORT}");
            Console.WriteLine("等待Python客户端连接...\r\n");

            // 防止控制台退出
            Console.ReadLine();
        }

        /// <summary>
        /// 客户端连接成功回调
        /// </summary>
        private static void TcpServer_ClientConnected(object sender, ConnectionEventArgs args)
        {
            Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 客户端已连接:{args.Client.IpPort}");
        }

        /// <summary>
        /// 客户端断开连接回调
        /// </summary>
        private static void TcpServer_ClientDisconnected(object sender, DisconnectionEventArgs args)
        {
            Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 客户端已断开:{args.Client.IpPort}");
        }

        /// <summary>
        /// 核心:接收并解析Python发送的TCP消息
        /// </summary>
        private static void TcpServer_MessageReceived(object sender, MessageReceivedEventArgs args)
        {
            try
            {
                // 接收的完整字节流
                byte[] receiveBytes = args.Data;

                // 校验:消息长度至少要包含完整包头
                if (receiveBytes.Length < HEAD_SIZE)
                {
                    Console.WriteLine("接收的数据不完整,缺少包头");
                    return;
                }

                #region 第一步:解析8字节包头
                // 1-1 前4字节:魔法标识 UFIX 校验
                byte[] magicCode = receiveBytes.Take(4).ToArray();
                string magicStr = Encoding.ASCII.GetString(magicCode);
                if (magicStr != "UFIX")
                {
                    Console.WriteLine($"非法数据包,魔法标识校验失败,收到:{magicStr}");
                    return;
                }

                // 1-2 后4字节:解析【大端序】的压缩体长度 (Python struct.I 对应 uint32 大端序)
                byte[] lenBytes = receiveBytes.Skip(4).Take(4).ToArray();
                // ★★★ 关键:Python的struct.pack是【大端序】,C#默认小端序,必须反转字节数组 ★★★
                if (BitConverter.IsLittleEndian) Array.Reverse(lenBytes);
                uint compressBodyLen = BitConverter.ToUInt32(lenBytes, 0);
                #endregion

                #region 第二步:解析zlib压缩包体
                // 提取包头后的压缩体字节数组
                byte[] compressBody = receiveBytes.Skip(HEAD_SIZE).Take((int)compressBodyLen).ToArray();
                if (compressBody.Length != compressBodyLen)
                {
                    Console.WriteLine($"压缩体长度不匹配,预期:{compressBodyLen},实际:{compressBody.Length}");
                    return;
                }
                #endregion

                #region 第三步:zlib解压 + UTF8解码(和Python端完全逆向操作)
                // Python: content.encode("utf-8") → zlib.compress → 发送
                // C#:      接收压缩体 → zlib.decompress → UTF8.GetString → 原始字符串
                byte[] decompressBody = Decompress(compressBody);
                string content = Encoding.UTF8.GetString(decompressBody);
                #endregion

                // 解析成功,打印结果
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 解析成功 → 原始内容:{content}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 解析消息异常:{ex.Message}");
            }
        }

        private static byte[] Decompress(byte[] data)
        {
            using (var compressedStream = new MemoryStream(data))
            using (var zipStream = new ZLibStream(compressedStream, CompressionMode.Decompress))
            using (var resultStream = new MemoryStream())
            {
                zipStream.CopyTo(resultStream);
                return resultStream.ToArray();
            }
        }

        public static byte[] Compress(byte[] data)
        {
            using (var ms = new MemoryStream())
            {
                using (var zlibStream = new ZLibStream(ms, CompressionLevel.Optimal))
                {
                    zlibStream.Write(data, 0, data.Length);
                }
                return ms.ToArray();
            }
        }
    }


}
import socket
import time
import struct
import zlib

SERVERIP = "localhost"
# 必填:	服务端端口
SERVERPORT = 5555
HEAD_SIZE = 8
RECEIVE_BUFFER_SIZE = 2048
test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
test_socket.connect((SERVERIP, SERVERPORT))
test_socket.setblocking(False)
time.sleep(1)
while True:
    content = '你好123'
    body = content.encode("utf-8")
    compressed_body = zlib.compress(body)
    compressed_body_len = len(compressed_body)
    format_str = f'4sI{compressed_body_len}s'
    data = struct.pack(format_str, b'UFIX',
                       compressed_body_len, compressed_body)
    test_socket.sendall(data)
    time.sleep(1)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions