【发布时间】:2017-05-30 17:25:18
【问题描述】:
在我的服务器应用程序的网络协议中,我在每个发送的包含长度的缓冲区的开头有 2 个字节。 TcpReadCallback 方法读取 BeginReceive 写入的字节,直到读取完整的缓冲区。但是,使用我的实现,数据包似乎丢失了,有时空缓冲区被发送到 ProcessReceiveBuffer,特别是当我发送消息的间隔小于 5 毫秒时,并且在通过 Internet 发送时更常见(将发生 10 秒左右)每半秒发送一次)。有没有人能发现我在这里做错了什么?
谢谢!
private Socket _tcpWorkSocket;
private byte[] _tcpWorkBuffer;
private byte[] _tcpReceiveBuffer;
public void BeginTcpReceive() {
if (!Connected)
return;
_tcpWorkBuffer = new byte[BufferSize]; // 1024
_tcpWorkSocket.BeginReceive(_tcpWorkBuffer, 0, BufferSize, 0, new AsyncCallback(TcpReadCallback), this);
}
private void TcpReadCallback(IAsyncResult ar) {
try {
if (!Connected)
return;
int readBytes = _tcpWorkSocket.EndReceive(ar);
if (readBytes > 0) {
byte[] buffer = new byte[readBytes];
Array.Copy(_tcpWorkBuffer, 0, buffer, 0, readBytes);
if (User != null)
User.SessionTimerReset();
Proccess_Buffer(buffer);
}
BeginTcpReceive();
}
catch(SocketException ex) {
Close(false);
}
catch (Exception ex) {
Logger.LogError("{0}: {1}\n{2}", ex.GetType(), ex.Message, ex.StackTrace);
Close(false);
}
}
private void Proccess_Buffer(byte[] buffer) {
if (!Receiving) {
Receiving = true;
_tcpPacketLength = BitConverter.ToUInt16(buffer, 0);
_tcpBytesNeeded = _tcpPacketLength;
_tcpCurIndex = 0;
_tcpReceiveBuffer = new byte[_tcpPacketLength];
}
int origSize = buffer.Length;
int copyLength = _tcpBytesNeeded;
if (_tcpBytesNeeded > BufferSize)
copyLength = BufferSize;
Array.Copy(buffer, 0, _tcpReceiveBuffer, _tcpCurIndex, copyLength);
_tcpCurIndex += buffer.Length;
_tcpBytesNeeded -= buffer.Length;
if (_tcpBytesNeeded <= 0) {
Receiving = false;
ProcessReceiveBuffer(_tcpReceiveBuffer, Protocal.Tcp);
}
if (origSize > buffer.Length) {
// next packet, incase 2 messages are sent in the same packet.
byte[] nextBuffer = new byte[buffer.Length - origSize ];
if (nextBuffer.Length > 1) {
Array.Copy(buffer, origSize , nextBuffer, 0, nextBuffer.Length);
Proccess_Buffer(nextBuffer);
}
else {
Logger.LogError("Next buffer length split!");
}
}
}
例子:
“received”后的第一个数字是客户端发送的顺序,第二个是大小。当通过 Internet 发送时,TCP 中经常会突然丢弃一些数据包。
[17:29:49]: received: 1349, 514
[17:29:50]: received: 1350, 514
[17:29:50]: received: 1351, 514
[17:29:51]: received: 1352, 514
[17:29:51]: received: 1353, 514
[17:29:52]: received: 1355, 514
[17:29:52]: Skipped! expected 1354, got 1355
[17:29:53]: received: 1357, 514
[17:29:53]: Skipped! expected 1356, got 1357
[17:29:54]: received: 1359, 514
[17:29:54]: Skipped! expected 1358, got 1359
[17:29:56]: received: 1362, 514
[17:29:56]: Skipped! expected 1360, got 1362
[17:29:56]: received: 1363, 514
[17:29:57]: received: 1364, 514
【问题讨论】:
-
您在 cmets 中的缓冲区大小为 1024。请尝试增大。 TCP 最大数据报大小 ~1500 字节最大。较大的消息被分解成小于 1500 的较小尺寸。路由器和 PC 可以将 1500 分解成更小的部分。您还可以获得包含 0 字节数据的保持活动消息。您的代码必须能够处理所有这些条件。