TCP服务器未正确读取固定大小的消息

RBa*_*iak 2 c# sockets tcp tcplistener

我将传感器数据从Android设备发送到C#中的TCP服务器.android客户端以32字节的固定大小块发送数据.

在服务器中,我读取数据,期望它将以完整包形式出现,但由于TCP是流协议,因此一些消息到达服务器分为两部分.我知道,因为我可以使用名为SocketSniff的软件观看它.

问题是我不知道如何在我的服务器上处理它.

我发现使用的所有例子NetworkStream.Read(),在该方法我必须通过字节来存储数据的读取,偏移和字节数来读取的阵列.这个字节数组必须具有已知大小,在我的例子中为32.

我不知道到达我服务器的邮件的实际大小,但它可能是以下情况之一.

  • 如果接收的数据大小为32字节,则一切正常.

  • 如果收到的数据大小超过32个字节,我想我正在丢失数据.

  • 如果接收的数据大小小于32个字节,假设为20个字节,则这些字节存储在我的数组中,并且数组的最后12个字节保留为零值.由于我可能真的收到一些零,所以无法知道我真正收到的大小,因此我无法将其与剩下的数据合并,这些数据应该在下次阅读时出现.

我处理接收的代码如下:

    int buffer = 32;
    ...
    private void HandleClientComm(object client)
    {
        TcpClient tcpClient = (TcpClient)client;
        NetworkStream clientStream = tcpClient.GetStream();

        byte[] message = new byte[buffer];
        int bytesRead;

        while (true)
        {
            bytesRead = 0;

            try
            {
                bytesRead = clientStream.Read(message, 0, message.Length);
            }
            catch
            {
                break;
            }

            if (bytesRead == 0)
            {
                // Connection closed
                break;
            }

            SensorData sensorData = ProcessTcpPacket(message);
        }
        tcpClient.Close();
    }
Run Code Online (Sandbox Code Playgroud)

有没有办法知道我在套接字中收到的数据大小?

zmb*_*mbq 6

嗯,是的,你有bytesRead变量 - 它保存从流中读取的字节数.您将最多读取message.Length字节,但您可以阅读更少.

请注意,如果有更多可用字节,则只需读取message.Length字节即可丢失它们.相反,它们将在您下次从流中读取时可用.

你需要做的是添加另一个while循环喜欢这个:

int messageRead = 0;

while(messageRead < message.Length)
{ 
    int bytesRead = clientStream.Read(message, messageRead, message.Length - messageRead);
    messageRead += bytesRead;
    if(bytesRead==0)
        return;   // The socket was closed
}
// Here you have a full message
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,分析bytesRead变量告诉我我缺少的东西,这段代码解决了管理任何大小的消息的所有问题. (2认同)