2012-07-05 20 views
5

Questa non è una domanda su come eseguire questa operazione, ma una domanda sul fatto che sia sbagliato ciò che sto facendo. Ho letto che non è possibile rilevare se un socket viene chiuso in modo imprevisto (come uccidere il processo server/client, tirare il cavo di rete) mentre si aspettano i dati (BeginReceive), senza l'uso di timer o messaggi inviati regolarmente, ecc. per un po 'di tempo ho usato il seguente setup per fare questo, e finora ha sempre funzionato perfettamente.Rilevamento disconnessione socket inatteso

public void OnReceive(IAsyncResult result) 
{ 
    try 
    { 
     var bytesReceived = this.Socket.EndReceive(result); 

     if (bytesReceived <= 0) 
     { 
      // normal disconnect 
      return; 
     } 

     // ... 

     this.Socket.BeginReceive...; 
    } 
    catch // SocketException 
    { 
     // abnormal disconnect 
    } 
} 

Ora, da quando ho letto che non è facilmente possibile, mi chiedo se c'è qualcosa di sbagliato con il mio metodo. È lì? O c'è una differenza tra i processi di uccisione e tirare i cavi e simili?

risposta

12

È perfettamente possibile e OK farlo. L'idea generale è:

Se EndReceive restituisce un valore diverso da zero, i dati in arrivo vengono elaborati.

Se EndReceive restituisce zero, l'host remoto ha chiuso la fine della connessione. Ciò significa che può ancora ricevere i dati inviati se è programmato per farlo, ma non può inviarne di propri in nessun caso. Di solito, quando ciò accade, chiudi anche la tua connessione, completando così uno spegnimento ordinato, ma non è obbligatorio.

Se EndReceive genera, si è verificata un'interruzione anomala della connessione (processo interrotto, interruzione del cavo di rete, perdita di alimentazione, ecc.).

Un paio di punti si deve prestare attenzione a:

  1. EndReceive può mai tornare inferiore a zero (il test nel codice è fuorviante).
  2. Se getta può lanciare altri tipi di eccezioni oltre a SocketException.
  3. Se restituisce zero, è necessario fare attenzione a smettere di chiamare BeginReceive; altrimenti inizierai un gioco di ping-pong infinito e privo di significato tra BeginReceive e EndReceive (che verrà visualizzato nell'utilizzo della CPU). Il tuo codice lo fa già, quindi non c'è bisogno di cambiare nulla.
+0

+1 in particolare perché mi piace come si inserisce "se è programmato per farlo". –

+2

+1 Vorrei anche sottolineare che non si dovrebbe mai avere una dichiarazione di cattura che cattura tutto a meno che non la rilanci. –

+1

@Alex Non sono d'accordo con il divieto di intercettare tutte le eccezioni a meno che non li si rilanci. Ho una classe TCP-server, che funziona molto come quella qui e non voglio alcuna eccezione casuale per terminare l'intera applicazione server. Ecco perché raccolgo tutte le eccezioni e le passo ad un gestore di eventi OnExceptionCaught, che dovrebbe essere collegato ad alcune funzionalità di registrazione ecc. – Algoman

Problemi correlati