質問
わかりました。コードから奇妙な例外がスローされ、長年悩まされてきました。
System.Net.Sockets.SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall
at System.Net.Sockets.Socket.Accept()
at System.Net.Sockets.TcpListener.AcceptTcpClient()
MSDN はこれに関してはあまり役に立ちません: http://msdn.microsoft.com/en-us/library/ms741547(VS.85).aspx そして、この問題のトラブルシューティングをどのように始めればよいのかさえわかりません。これは 1 日に 4 ~ 5 回しかスローされず、テスト環境では一度もスローされませんでした。本番サイトおよびすべての本番サイトのみ。
この例外について尋ねる投稿はたくさん見つかりましたが、何が原因で、どのように処理または防止するかについての実際の決定的な答えはありません。
コードは別のバックグラウンド スレッドで実行され、メソッドが開始されます。
public virtual void Startup()
{
TcpListener serverSocket= new TcpListener(new IPEndPoint(bindAddress, port));
serverSocket.Start();
次に、すべての新しい接続をジョブとして別のスレッド プールに配置するループを実行します。アプリのアーキテクチャによりさらに複雑になりますが、基本的には次のとおりです。
while (( socket = serverSocket.AcceptTcpClient()) !=null) //Funny exception here
{
connectionHandler = new ConnectionHandler(socket, mappingStrategy);
pool.AddJob(connectionHandler);
}
}
そこから、 pool
には独自のスレッドがあり、独自のスレッド内の各ジョブを個別に処理します。
私の理解では、AcceptTcpClient() はブロック呼び出しであり、何らかの形で winsock がスレッドにブロックを停止して実行を続行するように指示していると考えられます。しかし、なぜ?そして、私は何をすればいいのでしょうか?例外をキャッチして無視するだけですか?
そうですね、他のスレッドがソケットを閉じているとは思いますが、それが私のコードによるものではないことは確かです。私が知りたいのは次のとおりです。このソケットは接続しているクライアント (ソケットの反対側) によって閉じられていますか、それとも私のサーバーによって閉じられていますか。現時点では、この例外が発生するたびにリスニング ポートがシャットダウンされ、実質的にサービスが終了するためです。これが遠隔地から行われる場合、大きな問題になります。
あるいは、これは単に IIS サーバーがアプリケーションをシャットダウンし、バックグラウンド スレッドとブロック メソッドをすべてキャンセルしただけなのでしょうか?
解決
別のスレッドからserverSocketが閉じられている可能性はありますか?これにより、この例外が発生します。
他のヒント
これは、WSAcancelblablabla を回避するための私の解決策の例です。スレッドをグローバルとして定義すると、次のように invoke メソッドを使用できます。
private void closinginvoker(string dummy)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(closinginvoker), new object[] { dummy });
return;
}
t_listen.Abort();
client_flag = true;
c_idle.Close();
listener1.Stop();
}
これを呼び出した後、最初にスレッドを閉じてから、永遠ループ フラグを閉じて (存在する場合) それ以上の待機をブロックし、次に tcpclient を閉じてからリスナーを停止します。
これは次のような場合に発生する可能性があります serverSocket.Stop()
. 。いつでも電話したのは Dispose
と呼ばれていました。
待機スレッドの例外処理は次のようになります。
try
{
//...
}
catch (SocketException socketEx)
{
if (_disposed)
ar.SetAsCompleted(null, false); //exception because listener stopped (disposed), ignore exception
else
ar.SetAsCompleted(socketEx, false);
}
さて、何が起こったのかというと、前に例外が時々発生するということでした。 _disposed
true に設定されました。そこで私にとっての解決策は、すべてをスレッドセーフにすることでした。
こっちも一緒!しかし、「サーバー側」の ReceiveBuffer がクライアントからフラッディングされたことがわかりました。(私の場合、多数の RFID スキャナーが、次の TagCode が到着するまで送信を停止するのではなく、TagCode をスパム送信し続けました)
ReceiveBuffers を上げてスキャナーを再構成するのに役立ちました...
最近では、HttpWebRequest を使用して大きなファイルを PUT し、タイムアウト期間が経過したときにこの例外が発生しました。
私が確認した限り、アップロード時間が 3 秒を超える限り次のコードを使用すると、このエラーが発生します。
string path = "Reasonably large file.dat";
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
System.Net.HttpWebRequest req = (HttpWebRequest)System.Net.HttpWebRequest.Create("Some URL");
req.Method = "PUT";
req.Timeout = 3000; //3 seconds, small timeout to demonstrate
long length = new System.IO.FileInfo(path).Length;
using (FileStream input = File.OpenRead(path))
{
using (Stream output = req.GetRequestStream())
{
long remaining = length;
int bytesRead = 0;
while ((bytesRead = input.Read(buffer, 0, (int)Math.Min(remaining, (decimal)bufferSize))) > 0)
{
output.Write(buffer, 0, bytesRead);
remaining -= bytesRead;
}
output.Close();
}
input.Close();
}