首页 文章

TCP消息损坏

提问于
浏览
2

我有一个简单的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

谢谢

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

3 回答

  • 3

    这不是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;
    }
    
  • 1

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

  • 1

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

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

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

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

    希望这个暗示有所帮助 .

相关问题