繁体   English   中英

使用二进制协议的TCP帧

[英]TCP Framing with Binary Protocol

嘿,我在使用自定义二进制协议分隔数据包时遇到问题。 当前,服务器端代码如下所示。

    public void HandleConnection(object state)
    {
        TcpClient client = threadListener.AcceptTcpClient();
        NetworkStream stream = client.GetStream();
        byte[] data = new byte[4096];

        while (true)
        {
            int recvCount = stream.Read(data, 0, data.Length);
            if (recvCount == 0) break;
            LogManager.Debug(Utility.ToHexDump(data, 0, recvCount));
            //processPacket(new MemoryStream(data, 0, recvCount));
        }
        LogManager.Debug("Client disconnected");
        client.Close();
        Dispose();
    }

我一直在观看数据包的十六进制转储,有时整个数据包都以一发来,比如说全部20个字节。 其他时候它是零散的,我该如何缓冲此数据才能将其正确传递给我的processPacket()方法。 我只尝试使用单字节操作码标头,还应该向标头添加(ushort)contentLength之类的内容吗? 我正在尝试使协议尽可能轻巧,并且该系统不会发送非常大的数据包(<128字节)。

我正在测试的客户端代码如下。

    public void auth(string user, string password)
    {
        using (TcpClient client = new TcpClient())
        {
            client.Connect(IPAddress.Parse("127.0.0.1"), 9032);
            NetworkStream networkStream = client.GetStream();

            using (BinaryWriter writer = new BinaryWriter(networkStream))
            {
                writer.Write((byte)0); //opcode
                writer.Write(user.ToUpper());
                writer.Write(password.ToUpper());
                writer.Write(SanitizationMgr.Verify()); //App hash
                writer.Write(Program.Seed);
            }
        }
    }

我不确定这是否是造成混乱的原因,并且二进制协议在网络上似乎没有太多信息,尤其是涉及C#的地方。 任何评论将是有帮助的。 =)

解决了这个问题,不确定是否正确,但是似乎可以为我的处理人员提供所需的东西。

    public void HandleConnection(object state)
    {
        TcpClient client = threadListener.AcceptTcpClient();
        NetworkStream stream = client.GetStream();
        byte[] data = new byte[1024];

        uint contentLength = 0;
        var packet = new MemoryStream();
        while (true)
        {
            int recvCount = stream.Read(data, 0, data.Length);
            if (recvCount == 0) break;

            if (contentLength == 0 && recvCount < headerSize)
            {
                LogManager.Error("Got incomplete header!");
                Dispose();
            }

            if(contentLength == 0) //Get the payload length
                contentLength = BitConverter.ToUInt16(data, 1);

            packet.Write(data, (int) packet.Position, recvCount); //Buffer the data we got into our MemStream
            if (packet.Length < contentLength + headerSize) //if it's not enough, continue trying to read
                continue;

            //We have a full packet, pass it on
            //LogManager.Debug(Utility.ToHexDump(packet));
            processPacket(packet);

            //reset for next packet
            contentLength = 0;
            packet = new MemoryStream();
        }
        LogManager.Debug("Client disconnected");
        client.Close();
        Dispose();
    }

您应该将其视为流。 不要依赖任何特定的分块行为。

您所需的数据量是否始终相同? 如果不是,则应更改协议(如果可以),以长度为字节的逻辑“数据块”作为前缀。

在这种情况下,您将在一侧使用BinaryWriter ,因此将BinaryReader附加到TcpClient.GetStream()返回的NetworkStream似乎是最简单的方法。 但是,如果您真的想一次捕获一个块的所有数据,则应回到我的想法,即以数据的长度作为前缀。 然后循环播放直到获得所有数据。

(但是,请确保您有足够的数据来读取长度!如果您的长度前缀为4个字节,则您不想读取2个字节而错过下一个2个字节...)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM