Domanda

Ok, ho una strana eccezione generata dal mio codice che mi disturba da anni.

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 non è molto utile su questo: http://msdn.microsoft.com/en-us/library/ms741547(VS.85).aspx e non so nemmeno come iniziare a risolvere questo problema.Viene lanciato solo 4 o 5 volte al giorno e mai nel nostro ambiente di test.Solo nei siti produttivi e su TUTTI i siti produttivi.

Ho trovato molti post che chiedono informazioni su questa eccezione, ma nessuna risposta definitiva su cosa la stia causando e su come gestirla o prevenirla.

Il codice viene eseguito in un thread in background separato, il metodo inizia:

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

quindi eseguo un ciclo inserendo tutte le nuove connessioni come lavori in un pool di thread separato.Diventa più complicato a causa dell'architettura dell'app, ma fondamentalmente:

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

Da lì, il pool ha i propri thread che si occupano di ciascun lavoro nel proprio thread, separatamente.

Ciò che ho capito è che AcceptTcpClient() è una chiamata bloccante e che in qualche modo Winsock sta dicendo al thread di interrompere il blocco e continuare l'esecuzione.ma perché?E cosa dovrei fare?Basta catturare l'eccezione e ignorarla?


Bene, penso che qualche altro thread stia chiudendo il socket, ma certamente non proviene dal mio codice.Quello che vorrei sapere è:questo socket è chiuso dal client che si connette (sull'altro lato del socket) o è chiuso dal mio server.Perché così com'è in questo momento, ogni volta che si verifica questa eccezione, spegne la mia porta di ascolto, chiudendo di fatto il mio servizio.Se questo viene fatto da una postazione remota, allora è un grosso problema.

In alternativa, potrebbe trattarsi semplicemente del server IIS che chiude la mia applicazione e quindi annulla tutti i thread in background e i metodi di blocco?

È stato utile?

Soluzione

È possibile che serverSocket venga chiuso da un altro thread?Ciò causerà questa eccezione.

Altri suggerimenti

Questa è la mia soluzione di esempio per evitare WSAcancelblablabla:Definisci il tuo thread come globale, quindi puoi utilizzare il metodo di invocazione come questo:

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

Dopo averlo invocato, chiudi prima il thread e poi il flag del ciclo eterno in modo da bloccare ulteriori attese (se ce l'hai), quindi chiudi tcpclient e quindi interrompi il listener.

Ciò potrebbe accadere su a serverSocket.Stop().Che chiamavo ogni volta Dispose è stato chiamato.

Ecco come appariva la mia gestione delle eccezioni per il thread di ascolto:

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

Ora quello che è successo è che ogni tanto l'eccezione si verificava prima _disposed era impostato su vero.Quindi la soluzione per me era rendere tutto thread-safe.

Lo stesso qui!Ma ho scoperto che ReceiveBuffer sul "lato server" era inondato dai client!(Nel mio caso un gruppo di scanner RFID, che continuavano a inviare spam al TagCode, invece di interrompere l'invio fino all'arrivo del successivo TagCode)

Ha aiutato ad aumentare i ReceiveBuffers e a riconfigurare gli scanner...

Più recentemente ho visto questa eccezione quando utilizzavo HttpWebRequest per INSERIRE un file di grandi dimensioni e il periodo di timeout era trascorso.

Utilizzando il seguente codice finché il tempo di caricamento è > 3 secondi causerà questo errore, per quanto ho potuto vedere.

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();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top