Pregunta

Ok, tengo una extraña excepción lanzada desde mi código que me ha estado molestando durante años.

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 no es muy útil en esto: http://msdn.microsoft.com/en-us/library/ms741547(VS.85).aspx y ni siquiera sé cómo empezar a solucionar este problema.Sólo se lanza 4 o 5 veces al día y nunca en nuestro entorno de prueba.Sólo en los sitios de producción y en TODOS los sitios de producción.

Encontré muchas publicaciones preguntando sobre esta excepción, pero no hay respuestas definitivas sobre qué la está causando y cómo manejarla o prevenirla.

El código se ejecuta en un hilo de fondo separado, el método comienza:

public virtual void Startup()
    {
     TcpListener serverSocket= new TcpListener(new IPEndPoint(bindAddress, port));    
        serverSocket.Start();

luego ejecuto un bucle colocando todas las conexiones nuevas como trabajos en un grupo de subprocesos separado.Se vuelve más complicado debido a la arquitectura de la aplicación, pero básicamente:

   while (( socket = serverSocket.AcceptTcpClient()) !=null) //Funny exception here
    {
         connectionHandler = new ConnectionHandler(socket, mappingStrategy);
         pool.AddJob(connectionHandler);
    }
  }

A partir de ahí, el pool tiene sus propios subprocesos que se encargan de cada trabajo en su propio subproceso, por separado.

Tengo entendido que AcceptTcpClient() es una llamada de bloqueo y que de alguna manera winsock le está indicando al hilo que deje de bloquear y continúe con la ejecución.¿pero por qué?¿Y qué se supone que debo hacer?¿Simplemente detectar la excepción e ignorarla?


Bueno, creo que algún otro hilo está cerrando el socket, pero ciertamente no es de mi código.Lo que me gustaría saber es:¿Este socket está cerrado por el cliente que se conecta (en el otro lado del socket) o está cerrado por mi servidor?Porque tal como está en este momento, cada vez que ocurre esta excepción, cierra mi puerto de escucha, cerrando efectivamente mi servicio.Si esto se hace desde una ubicación remota, entonces es un problema importante.

Alternativamente, ¿podría ser simplemente que el servidor IIS cierre mi aplicación y, por lo tanto, cancele todos mis subprocesos en segundo plano y métodos de bloqueo?

¿Fue útil?

Solución

¿Es posible que el serverSocket se esté cerrando desde otro hilo?Eso provocará esta excepción.

Otros consejos

Esta es mi solución de ejemplo para evitar WSAcancelblablabla:Defina su hilo como global y luego puede usar un método de invocación como este:

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();
    }

Después de invocarlo, primero cierre el hilo y luego el indicador de bucle eterno para que bloquee la espera adicional (si lo tiene), luego cierre tcpclient y luego detenga el oyente.

Esto podría suceder en un serverSocket.Stop().A la que llamé cada vez Dispose fue llamado.

Así es como se veía mi manejo de excepciones para el hilo de escucha:

try
{
    //...
}
catch (SocketException socketEx)
{    
    if (_disposed)
        ar.SetAsCompleted(null, false); //exception because listener stopped (disposed), ignore exception
    else
        ar.SetAsCompleted(socketEx, false);
}

Ahora lo que pasó fue que, de vez en cuando, la excepción ocurría antes. _disposed se estableció en verdadero.Entonces, la solución para mí fue hacer que todo fuera seguro para subprocesos.

¡Aquí igual!¡Pero descubrí que el ReceiverBuffer en el 'lado del servidor' fue inundado por los clientes!(En mi caso, un grupo de escáneres RFID, que siguieron enviando spam con el TagCode, en lugar de dejar de enviar hasta que llegue el siguiente TagCode)

Ayudó a aumentar los ReceiverBuffers y reconfigurar los escáneres...

Más recientemente vi esta excepción al usar HttpWebRequest para PONER un archivo grande y se pasó el período de tiempo de espera.

Usar el siguiente código siempre que el tiempo de carga sea> 3 segundos causará este error, por lo que pude ver.

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();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top