TCP 接続の読み取り/書き込みにNetworkStream
(またはおそらく)を使用したい。Socket
複数のスレッドを処理したり、ネットワーク操作のブロックで一部のスレッドが停止する可能性がある場合にプログラムを停止する方法の問題に対処したりする必要がないように、非ブロック操作を使用したいと考えています。
NetworkStream.Readのドキュメントは、それが非ブロッキングであることを暗示しています (「読み取りに使用できるデータがない場合、Read メソッドは 0 を返します」)。
しかし、書くことはどうですか?Microsoft には、このテーマに関する通常の低品質のチュートリアルAsyncCallback
があり、すべての操作に対して面倒なメソッドを作成することを提案しています。このコールバック内のコードのポイントは何ですか?
client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None,
new AsyncCallback(SendCallback), client);
...
private static void SendCallback(IAsyncResult ar)
{
try {
Socket client = (Socket)ar.AsyncState;
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
のドキュメントにAsyncCallback
は、「非同期操作が完了したときに呼び出されるコールバック メソッド」であると書かれています。操作が既に完了している場合、なぜ電話する必要があるのSocket.EndSend(IAsyncResult)
でしょうか? 一方、のドキュメントにNetworkStream.BeginWrite
は、「デリゲートを実装するコールバック メソッドを作成し、AsyncCallback
その名前をBeginWrite
メソッドに渡す必要があります。少なくとも、状態パラメーターには . が含まれている必要がありますNetworkStream
。」と書かれています。
しかし、なぜ「しなければならない」のでしょうか。IAsyncResult
どこかに保管できないのでしょうか...
_sendOp = client.BeginSend(message, 0, message.Length, SocketFlags.None, null, null);
...そして定期的に完了したかどうかを確認しますか?
if (_sendOp.IsCompleted)
// start sending the next message in the queue
(これはポーリングを意味することは知っていますが、ほとんどの場合アクティブであると予想されるサーバーにあり、アイドル時にいくつかの Thread.Sleeps を計画しています。)
別の問題。送信するメッセージは、ヘッダー配列と本文配列に分割されます。2 つの BeginWrite を続けて発行できますか?
IAsyncResult ar1 = _stream.BeginWrite(header, 0, header.Length, null, null);
IAsyncResult ar2 = _stream.BeginWrite(msgBody, 0, msgBody.Length, null, null);
また、Socket と NetworkStream のどちらを使用するかについての意見も歓迎します。