2014-05-09 18 views
6

Il codice seguente, nonostante apparentemente chiudendo il socket UDP, lascia appeso e incapace di ricollegare allo stesso indirizzo/porto.(Apparentemente) chiusa normalmente classe UdpClient lascia la presa bloccata

Queste sono le variabili di classe che uso:

Thread t_listener; 
    List<string> XSensAvailablePorts; 
    private volatile bool stopT_listener = false;   
    volatile UdpClient listener; 
    IPEndPoint groupEP; 

ho creare e lanciare un nuovo thread con un metodo che gestirà la connessione socket e l'ascolto:

private void startSocketButton_Click(object sender, RoutedEventArgs e) 
     { 
      stopT_listener = false; 
      closeSocketButton.IsEnabled = true; 
      startSocketButton.IsEnabled = false; 
      t_listener = new Thread(UDPListener); 
      t_listener.Name = "UDPListenerThread"; 
      t_listener.Start(); 
     } 

Il metodo è il seguente (Io uso un timeOut sulla Ricezione per non lasciarlo bloccato se non viene inviato nulla sulla presa e viene emesso uno Stop):

private void UDPListener() 
    { 
     int numberOfPorts = XSensAvailablePorts.Count(); 
     int currAttempt = 0; 
     int currPort = 0; 
     bool successfullAttempt = false; 
     while (!successfullAttempt && currAttempt < numberOfPorts) 
     { 
      try 
      { 
       currPort = Int32.Parse(XSensAvailablePorts[currAttempt]); 
       listener = new UdpClient(currPort); 
       successfullAttempt = true; 
      } 
      catch (Exception e) 
      { 
       currAttempt++; 
      } 
     } 
     if (successfullAttempt) 
     { 
      //timeout = 2000 millis 
      listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 2000); 
      //Tried with and without, no change: listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 
      statusTB.Dispatcher.BeginInvoke((Action)delegate() { statusTB.Text = "Connected on port:" + currPort; }); 
      groupEP = new IPEndPoint(IPAddress.Parse("143.225.85.130"), currPort); 

      byte[] receive_byte_array; 
      try 
      { 
       while (!stopT_listener) 
       { 
        try 
        { 
         receive_byte_array = listener.Receive(ref groupEP); 
         if (receive_byte_array.Length == 0 || receive_byte_array == null) 
          continue; 

         ParseData(receive_byte_array, samplingDatagramCounter); 

        } 
        catch (SocketException ex) 
        { 
         if (ex.SocketErrorCode == SocketError.TimedOut) 
          continue; 
        } 


       } 
      } 
      catch (Exception e) 
      { 
       Debug.Print(e.Message); 
      } 
      finally 
      { 
       if (listener != null) 
       { 
        listener.Client.Shutdown(SocketShutdown.Both); 
        listener.Close(); 
       } 
      } 
     } 
     statusTB.Dispatcher.BeginInvoke((Action)delegate() { statusTB.Text = "Not Connected"; }); 
     return; 
    } 

posso ordinare il filo/presa per fermare con questo metodo:

private void closeSocketButton_Click(object sender, RoutedEventArgs e) 
     { 
      stopT_listener = true; 
      closeSocketButton.IsEnabled = false; 
      startSocketButton.IsEnabled = true; 
      t_listener.Join(); 
      if (listener.Client != null) 
      { 
       listener.Client.Shutdown(SocketShutdown.Both); 
       listener.Close(); 
      } 
      if (t_listener.IsAlive) 
      { 
       t_listener.Abort(); 
       statusTB.Text = "Aborted"; 
      } 
      else 
       statusTB.Text = "Not Connected"; 
     } 

Nonostante la registrazione di debug che la presa è stato chiuso, se riprovo collegare alla stessa porta, non sono in grado di farlo perché solleva un SocketException che dice che solo un uso di porta/indirizzo è normalmente permesso.

+0

Potrebbe essere, che cosa 'listener.Client' è' null' quando si fa clic sul pulsante? Non chiamerai 'listener.Close()' allora. – Sinatr

+0

@Sinatr Ho controllato il debug e non è il caso. –

+0

. Chiudere() dovrebbe eliminare completamente l'oggetto. deve essere qualcos'altro, come non chiudere effettivamente il socket (probabilmente a causa di qualche eccezione non gestita e semplicemente ignorata). non so da quando ho appena usato il metodo .BeginReceive async per gestire i dati. ; p – porkchop

risposta

0

ho messo il codice che hai fornito in una forma semplice per eseguirlo e ... io non può riprodurre direttamente il vostro problema. Non ho comunque inviato dati al client, ma per quanto ho capito non dovrebbe cambiare nulla dato che è UDP e stiamo investigando (ri) aprendo socket, non trasmettendo dati.

Cliccando i pulsanti Start/Stop il socket è sempre correttamente aperto e chiuso, la riapertura funziona come previsto. Per me l'unico modo per forzare il SocketException lei ha citato è stato quello di introdurre qualche evidente abuso di logica presa:

  1. eseguire due istanze di applicazione e fare clic su Avvia in entrambi.
  2. Rimuovere tutte le occorrenze di Arresto e Chiusura (l'arresto non chiude il socket).
  3. Applicazione in esecuzione, apertura socket, chiusura dell'app senza chiusura socket, esecuzione di app di nuovo, tentativo di aprire socket.

Solo le modifiche apportate nel codice erano la rimozione della riga ParseData (...) e l'aggiunta di alcune porte all'elenco XSensAvailablePorts.

Potete controllare se la porta è ancora aperta dopo aver apparentemente chiude? È possibile utilizzare netstat -an o un eccellente strumento ProcessExplorer. Puoi anche controllare se il thread t_listener sta terminando correttamente (Task Manager standard o ProcessExplorer può aiutarti).

+1

Non ho accesso all'HW/SW a cui stavo comunicando (come potreste aver capito dal nome delle variabili sto accedendo al flusso di socket della tuta XSens per il body tracking), ma lo controllerò la prossima settimana . Ho avuto così tanti problemi con il flusso di dati di questo componente che sospetto possa essere colpa del server qualcosa va in tilt. –

0

impostare l'oggetto ascoltatore a NULL in modo che la risorsa viene rilasciata, che dovrebbe anche liberare la connessione.

+0

Piuttosto che impostare l'oggetto su null e attendere che il GC liberasse risorse, ho forzato il rilascio delle risorse con Close()/Dispose(), ma non ha funzionato neanche. –

0

Ho lo stesso problema, e il problema è in UDPClient.Receive(), lei mantenere la presa in stato di usato anche si chiama Primo/spegnimento/...`

try{ // receive loop} 
catch{} 
finally { 
UDP_Listner.Close(); 
        UDP_Listner = null; 
       } 

EDIT:

t_listener = new Thread(UDPListener);//replace by : 
t_listener = new Thread(new ThreadStart(UDPListener)); 

`

in modo sicuro vicino presa & filo (http://msdn.microsoft.com/en-us/library/system.threading.threadstart(v=vs.110).aspx)

0

Ho lo stesso problema, io sono il programmatore più sicuro, ho sempre vicino tutto bene. tuttavia ho trovato che la classe .net non chiude il socket abbastanza velocemente. perché se vado lento non succede, ma se apro e chiudo (ripulisci completamente) e lo apro velocemente, ottengo lo stesso errore. soprattutto se l'utente desidera eseguire di nuovo lo stesso codice e riaprire la porta.

+0

È una risposta o un commento? – heltonbiker

0

Potrebbe essere una vecchia risposta, ma nel tentativo di trovare una porta utilizzabile, ma che non è riuscita, dispongo l'istanza del listener che hai testato prima della successiva iterazione.

  try 
      { 
       currPort = Int32.Parse(XSensAvailablePorts[currAttempt]); 
       listener = new UdpClient(currPort); 
       successfullAttempt = true; 
      } 
      catch (Exception e) 
      { 
       currAttempt++; 

       if(listener != null) 
       { 
        listener.Close(); 
       } 
      } 
Problemi correlati