我们有一个 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
// ...
}
where是从流中提取固定大小标头ReadHeader
的扩展方法。NetworkStream
异步版本的问题
在我们使用BeginRead
and的异步版本中,EndRead
读取回调可能会被缓冲区中的部分接收消息调用。由于回调是在从流中提取数据后调用的,因此不可能将部分消息留在流中以供下一个回调使用。但是,我们必须将这部分数据保留到下一次回调,以便以后处理。
似乎唯一的解决方案是将部分数据字节复制到不同的缓冲区,或者在BeginRead
调用下一个缓冲区之前将它们移动到接收缓冲区的底部。这是正确的,还是有更常见的技术来处理这种情况?