TCP消息损坏

时间:2011-08-31 12:52:21

标签: c# .net sockets asynchronous tcp

我有一个简单的TCP服务器,通过GPRS与某些设备通信。它长时间正常工作没有任何问题。现在,设备(客户端设备,发送数据)发生了变化,它们发送的数据比以前多得多,TCP消息大小可能比之前大10倍。早期它是最大1024字节/数据消息,现在它可以超过1万字节/消息。

正如我所看到的 - 正如TCP所预测的那样 - 有很多消息被“破坏”,所以不是完整的消息,只有一部分到达,后来可以来到另一部分等。

我认为我的服务器 - 基于异步模式 - 以错误的方式处理这种情况,我认为该错误存在于我的RecieveCallBack函数中。我找不到正确处理这种情况的方法。我怎么能这样做?

这是我的RecieveCallBack功能:

public void RecieveCallBack(IAsyncResult ar)
    {
        StateObject state = (StateObject)ar.AsyncState;

        try
        {
            Socket handler = state.WorkSocket;

            int read = handler.EndReceive(ar);

            if (read > 0)
            {
                var data = new byte[read];
                Array.Copy(state.Buffer, 0, data, 0, read);
            }
            else
            {
                if ((handler.Connected == false) || (handler.Available == 0))
                {
                    Close(state);
                    return;
                }
            }
        }
        catch (System.Net.Sockets.SocketException)
        {
            Close(state);
        }
        catch (System.Exception exc)
        {
            Debug.Assert(false, exc.Message);
            HandleSocketError(state, exc);
        }
    }

.NET4 / C#/ VS2010

由于

更新 客户端可以连接时连接,因此由GSM网络决定。它们甚至可以连接几天,并且每隔几分钟就会发送数据。客户端设备的协议不同,存在具有不同种类协议的不同类型的设备。其中一个在消息末尾有分隔符和CRC,其他则没有。

3 个答案:

答案 0 :(得分:3)

您需要message framing。协议必须指定消息的大小 - 通常是常量已知大小,长度前缀或使用消息分隔符。

答案 1 :(得分:1)

TCP中没有数据包。它是一种面向流的协议。这意味着当您阅读套接字时,您可以获得比预期更少的数据。您需要检查读取大小,如果您有一个简短的读取,则再次读取其余数据。

以C:

为例
int read_data(int sock, int size, unsigned char *buf) {
   int bytes_read = 0, len = 0;
   while (bytes_read < size && 
         ((len = recv(sock, buf + bytes_read,size-bytes_read, 0)) > 0)) {
       bytes_read += len;
   }
   if (len == 0 || len < 0) doerror();
   return bytes_read;
}

答案 2 :(得分:1)

我不确定应用程序的其余部分是怎么看的,但我认为问题出在以下几行: -

Array.Copy(state.Buffer, 0, data, 0, read);

如果数据包被分段,即对于同一连接多次调用接收回调,则state.Buffer将被最后接收的数据包覆盖,这是在state.Buffer中将数据复制到偏移0时。

根据您的需求,您可能需要在StateObject中使用更多状态:)因此您可以附加数据而不是覆盖。

希望这个暗示有所帮助。