我们有一个C#应用程序,它使用一个相对简单的协议通过TCP / IP与设备通信,该协议由一系列消息组成,这些消息具有固定大小的头和可变长度的有效负载。标头包含有效负载的长度。
最近我们将编程模型从同步转换为异步,现在有一个有趣的问题:如何处理部分接收的消息。
同步代码
public void ReceiveMessage(NetworkStream stream)
{
// Read the header from the stream
MessageHeader header = stream.ReadHeader();
int payloadBytesRead = 0;
byte[] buffer = new byte[header.PayloadSize];
// Keep reading from the stream until the payload
// is fully extracted
while (payloadBytesRead < header.PayloadSize)
{
payloadBytesRead += stream.Read(buffer, payloadBytesRead, header.PayloadSize - payloadBytesRead);
}
MessagePayload = new MessagePayload(buffer);
// Do something with the message here
// ...
}
其中ReadHeader
是NetworkStream
上的一种扩展方法,用于从流中提取固定大小的标头。
异步版本问题
在我们使用BeginRead
和EndRead
的异步版本中,有可能在缓冲区中使用部分接收的消息调用读取回调。由于在之后调用了回调,因此从流中提取数据,因此无法在流中留下部分消息以进行下一次回调。但是,我们必须将此部分数据保留到下一个回调,以便以后进行处理。
似乎唯一的解决方案是将部分数据字节复制到不同的缓冲区,或者在调用下一个BeginRead
之前将它们移到接收缓冲区的底部。这是正确的,还是有更常用的技术来处理这种情况?