TCP 消息损坏
我有一个简单的 TCP 服务器,它通过 GPRS 与一些设备进行通信。可以长期正常工作,没有任何问题。如今,设备(发送数据的客户端设备)发生了变化,它们发送的数据比以前多得多,并且 TCP 消息大小可能比以前大 10 倍。早些时候,每条数据消息的最大长度为 1024 字节,现在可以超过 10,000 字节/消息。
正如我所看到的 - 正如 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,其他则没有。
I have a simple TCP server that communicates with some devices via GPRS. It works correctly without any problem for a long time. Nowdays there is a change in the devices (client devices, that send data) and they send lot more data than earlier and TCP message size can be 10 times bigger than earlier. Earlier it was max 1024 bytes/data message, now it can be more than 10 thousand bytes/message.
As I see - as the nature of TCP predicted - there are a lot of messages that are 'broken', so instead of a complete message only a part of that arrives, and later can come the other part etc.
I think my server - that is based on asynchronous pattern - handles this situation in a wrong way and I think the bug is in my RecieveCallBack function. I could not find to correct way to handle this situation. How can I do this?
Here is my RecieveCallBack function:
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
Thanks
UPDATE:
Clients are connected as they can be connected, so it is up to the GSM network. They can be connected even for days and they send data at every minutes. The protocol of the client devices is different, there are different kind of devices with different kind of protocols. One of them has delimiter and CRC at the end of the message, others does not have.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您需要消息框架。协议必须指定消息的大小 - 通常是众所周知的恒定大小、长度前缀或使用消息分隔符。
You need message framing. The protocol must specify how large the messages are - usually either a constant well-known size, a length prefix, or using message delimiters.
TCP 中没有数据包这样的东西。它是一个面向流的协议。这意味着当您读取套接字时,您可以获得的数据比您预期的要少。您需要检查读取大小,如果读取时间较短,则再次读取其余数据。
以 C 语言为例:
The is no such thing as packets in TCP. It is a stream oriented protocol. That means when you read the socket you can get less data than you're expecting. You need to check the read size and if you got a short read then read again for the rest of the data.
For an example in C:
我不确定应用程序的其余部分看起来如何,但我认为问题出在以下行:-
如果数据包分段,即对同一连接多次调用接收回调,则状态。缓冲区将被最后一次覆盖收到数据包,这是因为您将数据复制到 state.Buffer 中的偏移量 0。
根据您的需求,您可能需要 StateObject 中的更多状态:),以便您可以附加数据而不是覆盖。
希望这个提示有帮助。
I am not sure how the rest of the application looks but I think the problem is with the following line :-
If a packet is fragmented i.e the receive callback is called multiple times for the same connection the state.Buffer will be overwritten with the last received packet, this as you copy data to offset 0 in state.Buffer.
Depending on what your needs are you need to probably need more state in StateObject :) so you can append the data rather than overwrite.
Hope this hint helps.