当然、データがない場合、BeginReceive()
は決して終了しません。 MSDN Close()
を呼び出すとBeginReceive()
が中止されることをお勧めします 。
ただし、ソケットでClose()
を呼び出すと、Dispose()
も実行されます( this great ansewr 、その結果、EndReceive()
は、オブジェクトが既に破棄されている(そして破棄されている)ため、例外をスローします。
どうすればいいですか?
これは(非常に愚かな)設計によるもののようです。この例外をスローし、コードでキャッチする必要があります。
MSDNは確かにそれについて沈黙しているように見えますが、別の非同期ソケットメソッド BeginConnect() のドキュメントを見ると、次のことがわかります。
BeginConnect()メソッドの保留中の呼び出しをキャンセルするには、ソケットを閉じます。非同期操作の進行中にClose()メソッドが呼び出されると、BeginConnect()メソッドに提供されるコールバックが呼び出されます。 EndConnect(IAsyncResult)メソッドを次に呼び出すと、ObjectDisposedExceptionがスローされ、操作がキャンセルされたことを示します。
それがBeginConnectの適切な方法である場合、BeginReceiveの場合も同様です。通常のフローの一部としてユーザーに例外をスローさせてキャッチさせると、デバッガーが煩わしいものになるため、これはMicrosoftの非同期APIの部分では確かに貧弱な設計です。 Close()がそもそも操作を完了するため、操作が完了するまで「待機」する方法はありません。
SocketOptionsの使用を推奨する人がいないことに驚いています。
スタックに送信または受信操作が行われると、スタックはソケットのソケットオプションによってバインドされます。
小さな送信または受信タイムアウトを使用し、操作の前にそれを使用して、同じ操作の間にそれがより短いまたはより長いものに変更されたかどうかを気にしないでください。
これにより、コンテキストの切り替えが多くなりますが、どのプロトコルでもソケットを閉じる必要はありません。
例えば:
1)小さなタイムアウトを設定する
2)操作を実行する
3)タイムアウトを大きく設定する
これは、Blocking = falseの使用に似ていますが、指定した自動タイムアウトがあります。
この問題の私の解決策は、ここで読むことができます(Pavel Radzivilovskyのコメントをここで使用): dpClient.ReceiveAsync早期終了を修正
TCPソケット接続の場合、 Connected プロパティを使用して、破棄されたメソッドにアクセスする前にソケットの状態を確認できます。MSDNごと:
「Connectedプロパティは、最後のI/O操作の時点でのソケットの接続状態を取得します。falseを返す場合、ソケットは接続されていなかったか、接続されていません。」
「もはや接続されていません」と表示されているため、Close()が以前にソケットで呼び出されたことを意味します。受信コールバックの開始時にソケットが接続されているかどうかを確認すると、例外はありません。