web-dev-qa-db-ja.com

非同期で処理する場合のTcpClientとソケット

これはまだ別のTcpClientとソケットではありません。

TcpClientは、開発を容易にするためにSocketクラスを囲むラッパーであり、基になるSocketも公開します。

まだ...

TcpClientクラスのMSDNライブラリページでは、次のコメントを読むことができます。

TcpClientクラスは、同期ブロッキングモードでネットワークを介してストリームデータを接続、送信、および受信するための簡単なメソッドを提供します。

そしてSocketクラスの場合:

Socketクラスを使用すると、ProtocolType列挙にリストされている任意の通信プロトコルを使用して、同期データ転送と非同期データ転送の両方を実行できます。

TcpCientのみを介して非同期で一部のデータを送受信するには、GetStreamを呼び出す必要があります。それには、TAPパターンに従って、ReadAsyncメソッドとWriteAsyncメソッドを呼び出して、データを非同期で読み書きできる基本のNetworkStreamを取得します。 (潜在的に非同期/待機コンストラクトを使用)。

ソケットを介して一部のデータを非同期で送受信するには(私は専門家ではありませんが、正しく理解していると思います)、BeginRead/EndRead BeginWrite/EndWrite(または単にReadAsyncまたはWriteAsync .. TAPパターンを公開しない-つまり、タスクを返さない..紛らわしい)。

まず、.NET 4.5のSocketクラスがTAPパターンを実装していない理由、つまりReadAsyncとWriteAsyncがTaskを返す(後方互換性を維持するために異なる方法で呼び出された場合のイベント)?

とにかく、APMモデルとメソッドのペアからタスクメソッドを構築するのは簡単なので、この非同期メソッド(読み取り用)をReadAsyncTAP(タスクを返す)と呼びます。

OK ?それでは、クライアントメソッドasync Task<Byte[]> ReadNbBytes(int nbBytes)をコード化して、コードから呼び出し、ネットワークから特定のバイト数を非同期で読み取るとします。

TcpClientのみに基づくこのメソッドの実装は、GetStreamを呼び出すことによってNetworkStreamを取得し、バッファがいっぱいになるまでReadAsync呼び出しを待機する非同期ループを含みます。

ソケットに基づくこのメソッドの実装には、バッファがいっぱいになるまでReadAsyncTAPで待機する非同期ループが含まれます。

結局のところ、クライアントコードの観点からは、違いはないと思います。どちらの場合も、await ReadNbBytesはすぐに「戻ります」。しかし、それは舞台裏で違いを生むと思います... NetworkStreamに依存しているTcpClientの場合、ソケットを直接使用する場合と比較して、読み取りが何らかの理由でブロックされるか、ブロックされませんか?そうでない場合、同期ブロッキングモードについて話すときにTcpClientに対して行われた発言が間違っていますか?

誰かが明確にできれば大いに感謝されます!

ありがとう。

25
darkey

TcpClientストリームの非同期I/Oはブロックされません。 MSDNドキュメントが間違っているようです(NetworkStreamの非同期I/O呼び出しに従って、Reflectorでこれを確認できます)。

Streamタイプは「興味深い」:デフォルトでは、Stream基本クラスは、同期I/Oでスレッドプールスレッドをブロックすることにより、非同期I/Oを実装します。したがって、同期メソッドのみを提供するMemoryStreamのようなもので非同期I/Oを実行する必要はありません。

NetworkStreamdoes非同期I/Oを提供するため、NetworkStreamインスタンスの非同期I/Oは実際には非同期です。ただし、常にそうであるとは限りません。特にFileStream通常はnot非同期ですが、インスタンスを適切に構築した場合 です。

SocketにTAPメソッドがない理由について:これは非常に良い質問です!見落としと思いましたが、.NET 4.5がリリースされたので、わざと間違えたようです。 APIを過度に複雑にしたくないのかもしれません-ソケットには同じ操作セットをカバーする同期およびtwo非同期APIがすでにあります(SendSendToReceiveReceiveFromConnectAcceptDisconnect )。 TAPは、そのフルセットに対して2つの追加の非同期APIを必要とします。それは少なくとも興味深いネーミング状況を引き起こします(*Asyncの名前は既に使用されており、さらに2つ追加されます*Async各操作の名前)。

補足:「追加の」APIは、高性能非同期Socket通信用です。それらは、SocketAsyncEventArgsを使用します。これは、簡単には使用できませんが、メモリのガベージは少なくなります。 TAP APIがSocketに追加された場合、使いやすいバージョン(Begin/Endのラッピング)と高性能バージョン(Asyncのラッピング)の両方を提供する必要があります。

SocketのTAPメソッドを作成することに興味がある場合は、Stephen Toubの Awaiting Socket Operations (彼は高性能APIのラッパーのみを提供しています)から始めるのが良いでしょう。私は、async- enabledソケットに似たものを使用しています。

27
Stephen Cleary