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

时间:2012-03-09 19:57:00

标签: 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();
    }

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

1 个答案:

答案 0 :(得分:6)

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

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

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

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