Ответ 1
Возможно ли, что serverSocket закрывается из другого потока? Это вызовет это исключение.
Хорошо, у меня есть странное исключение из моего кода, который беспокоил меня целую вечность.
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, и я даже не знаю, как начать устранение этой проблемы. Он выпускается только 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();
}
После того, как вы его вызовете, сначала закройте поток, а затем флаг forever loop, чтобы заблокировать дальнейшее ожидание (если оно у вас есть), затем закройте 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 и переконфигурировать сканеры...