我有一个简单的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,其他则没有。
答案 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中使用更多状态:)因此您可以附加数据而不是覆盖。
希望这个暗示有所帮助。