Хорошо, у меня возникло странное исключение из моего кода, которое беспокоило меня целую вечность.
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 закрывается из другого потока? Это вызовет это исключение.
Нет, пока другой поток имеет ссылку на объект сокета, он может закрыть его.
Это могло произойти на 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)
Помогло поднять буферы приема и перенастроить сканеры ...
Это мой пример решения, чтобы избежать WSAcancelblablabla: Определите свой поток как глобальный, тогда вы можете использовать метод вызова следующим образом:
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, чтобы он заблокировал дальнейшее ожидание (если он у вас есть), затем закройте tcpclient и остановите слушателя.
InvokeRequired связывает ваше решение с winforms. Что делать, если код выполняется в службе Windows?
Совсем недавно я видел это исключение при использовании 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();
}
Хм, я не понимаю, как это может мне помочь (у меня та же ошибка). Кстати, шаблон «using» уже вызывает для вас output.Close(); и input.Close();, так что не нужно делать это самостоятельно, иначе он будет вызываться дважды.
Скажи, что это так. Как закрыть его из другой ветки? Должен ли сокет быть «энергозависимым»?