固定サイズのヘッダーと可変長のペイロードを持つ一連のメッセージで構成される比較的単純なプロトコルを使用して、TCP/IP 経由でデバイスと通信する C# アプリケーションがあります。ヘッダーにはペイロードの長さが含まれます。
最近、プログラミング モデルを同期から非同期に変更しましたが、興味深い問題が発生しました。それは、部分的に受信したメッセージをどのように処理するかということです。
同期コード
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
とを使用する非同期バージョンではEndRead
、バッファ内の部分的に受信されたメッセージで読み取りコールバックが呼び出される可能性があります。データがストリームからプルされた後にコールバックが呼び出されるため、次のコールバックのために部分的なメッセージをストリームに残すことはできません。ただし、後で処理できるように、次のコールバックまでこの部分的なデータを保持する必要があります。
唯一の解決策は、部分的なデータ バイトを別のバッファにコピーするか、次のバッファBeginRead
が呼び出される前に受信バッファの一番下にシフトすることです。これは正しいですか、またはこのシナリオを処理するためのより一般的な手法はありますか?