[英]Asynchronous socket unexpected packet with BeginReceive \ EndReceive
I need to receive an async message. 我需要接收异步消息。
In all messages, first 2 byte indicate the length of next byte array. 在所有消息中,前2个字节指示下一个字节数组的长度。 My problem is that in few case I receive unexpected packets.
我的问题是,在少数情况下,我会收到意外的数据包。
If I use Thread.Sleep(200)
this problems does't happen, or happens rarely. 如果我使用
Thread.Sleep(200)
不会发生或很少发生此问题。
Where am I wrong? 我哪里错了?
protected void StartListening()
{
StateObject state = new StateObject() { ProcessHeader = true };
state.PrepareBuffer(HeaderLength);
lock (_secureConnection)
_secureConnection.BeginReceive(state.Buffer, 0, HeaderLength, 0, new AsyncCallback(ReadCallback), state);
}
private void ReadCallback(IAsyncResult ar)
{
if (_disposing)
return;
StateObject state = (StateObject)ar.AsyncState;
try
{
lock (_secureConnection)
_secureConnection.EndReceive(ar);
if (state.ProcessHeader)
{
state.ProcessHeader = !state.ProcessHeader;
var bodyLength = GetBodyLength(state.Buffer);
//Thread.Sleep(200);
state.CompleteMessage.AddRange(state.Buffer);
state.PrepareBuffer(bodyLength);
lock (_secureConnection)
_secureConnection.BeginReceive(state.Buffer, 0, bodyLength, 0, new AsyncCallback(ReadCallback), state);
}
else
{
state.CompleteMessage.AddRange(state.Buffer);
ProcessMessage(state.CompleteMessage); //process this message
//Thread.Sleep(200);
state.ProcessHeader = !state.ProcessHeader;
state.CompleteMessage.Clear();
state.PrepareBuffer(HeaderLength);
lock (_secureConnection)
_secureConnection.BeginReceive(state.Buffer, 0, HeaderLength, 0, new AsyncCallback(ReadCallback), state);
}
}
catch (Exception e)
{
Close(true);
}
}
class StateObject
{
public StateObject()
{
ProcessHeader = true;
}
public byte[] Buffer { get; private set; }
public bool ProcessHeader { get; set; }
public List<byte> CompleteMessage = new List<byte>();
public void PrepareBuffer(int size)
{
Buffer = new byte[size];
}
}
You are assuming that TCP is a message-based protocol. 您假设TCP是基于消息的协议。 It is a stream of bytes, though.
不过,它是字节流。 Your reads can read any amount greater than zero.
您的读数可以读取大于零的任何数量。 This is just like with a FileStream.
就像FileStream一样。 Files do not have messages, either.
文件也没有消息。
Your code has to deal with that fact. 您的代码必须处理这个事实。 Search for "TCP message framing".
搜索“ TCP消息框架”。
SOLUTION FOUND After a long time, i've written a good solution, I hope to help someone. 找到的解决方案经过很长一段时间,我写了一个很好的解决方案,希望对您有所帮助。 Thank you very much for your suggestions.
非常感谢您的建议。
int HeaderLength = 2;
int bodyLength;
int bytesReceived;
int totalBytesReceived;
protected void StartListening()
{
StateObject state = new StateObject() { ProcessHeader = true };
state.PrepareBuffer(HeaderLength);
lock (_secureConnection)
_secureConnection.BeginReceive(state.Buffer, 0, HeaderLength, 0, new AsyncCallback(ReadCallback), state);
}
/// <summary>
/// Reads the callback.
///
/// A message is in this form:
///
/// 2 bytes indicate the leght of body message (n)
/// n bytes for body message
///
/// </summary>
/// <param name="ar">IAsyncResult.</param>
private void ReadCallback(IAsyncResult ar)
{
if (_disposing)
return;
StateObject state = (StateObject)ar.AsyncState;
try
{
lock (_secureConnection)
bytesReceived = _secureConnection.EndReceive(ar);
if (state.ProcessHeader) //In this phase I receive 2 bytes that indicate the total length of the next message
{
state.ProcessHeader = !state.ProcessHeader;
bodyLength = GetBodyLength(state.Buffer); //I interpret 2 bytes to know body message length
state.CompleteMessage.AddRange(state.Buffer);
state.PrepareBuffer(bodyLength);
totalBytesReceived = bytesReceived = 0;
lock (_secureConnection)
_secureConnection.BeginReceive(state.Buffer, 0, bodyLength, 0, new AsyncCallback(ReadCallback), state);
}
else //In this phase I receive the message, with one or more recursive CallBack
{
state.CompleteMessage.AddRange(state.Buffer.ToList().GetRange(0, bytesReceived));
totalBytesReceived += bytesReceived;
int totalBytesMissing = bodyLength - totalBytesReceived;
if (totalBytesReceived < bodyLength)
{
state.PrepareBuffer(totalBytesMissing);
lock (_secureConnection)
_secureConnection.BeginReceive(state.Buffer, 0, totalBytesMissing, 0, new AsyncCallback(ReadCallback), state);
return;
}
//totalMessageLenght = body length plus first 2 bytes indicate body length
int totalMessageLenght = bodyLength + 2;
var completeMessage = state.CompleteMessage.GetRange(0, totalMessageLenght).ToList();
ProcessMessage(completeMessage);
state.ProcessHeader = !state.ProcessHeader; //I prepare Callback to read 2 bytes indicate the total length of the next message
state.CompleteMessage.Clear();
state.PrepareBuffer(HeaderLength);
lock (_secureConnection)
_secureConnection.BeginReceive(state.Buffer, 0, HeaderLength, 0, new AsyncCallback(ReadCallback), state);
}
}
catch (Exception e)
{
Close(true);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.