2012-08-06 12 views
9

Sto lavorando su una relazione client/server che intende trasmettere i dati avanti e indietro per un periodo di tempo indeterminato.Come rilevare una disconnessione Disconnetti in C#

Il problema che sto tentando di superare è sul lato client, poiché non riesco a trovare un modo per rilevare una disconnessione.

Ho preso un paio di passaggi alle soluzioni di altre persone, che vanno dalla cattura di eccezioni IO, al polling del socket su tutti e tre i SelectModes. Ho anche provato a utilizzare una combinazione di un sondaggio, con un controllo sul campo "Disponibile" del socket.

// Something like this 
Boolean IsConnected() 
{ 
    try 
    { 
     bool part1 = this.Connection.Client.Poll(1000, SelectMode.SelectRead); 
     bool part2 = (this.Connection.Client.Available == 0); 

     if (part1 & part2) 
     { 
      // Never Occurs 
      //connection is closed 
      return false; 
     } 
     return true; 
    } 
    catch(IOException e) 
    { 
     // Never Occurs Either 
    } 
} 

Sul lato server, un tentativo di scrivere un carattere 'vuoto' (\ 0) al client costringe un'eccezione IO e il server in grado di rilevare che il client si è disconnesso (abbastanza facile concerto).

Sul lato client, la stessa operazione non fa eccezione.

// Something like this 
Boolean IsConnected() 
{ 
    try 
    { 

     this.WriteHandle.WriteLine("\0"); 
     this.WriteHandle.Flush(); 
     return true; 
    } 
    catch(IOException e) 
    { 
     // Never occurs 
     this.OnClosed("Yo socket sux"); 
     return false; 
    } 
} 

Un problema che credo sto avendo nel rilevare una disconnessione tramite un sondaggio, è che posso abbastanza facilmente incontrare un falso su una SelectRead, se il mio server non ha scritto ancora nulla di nuovo al cliente dal l'ultimo controllo ... Non so cosa fare qui, ho inseguito ogni opzione per fare questo rilevamento che posso trovare e niente è stato al 100% per me, e in definitiva il mio obiettivo qui è quello di rilevare un server (o una connessione) fallimento, informare il cliente, aspettare di riconnettersi, ecc. Quindi sono sicuro che potete immaginare che questo è un pezzo integrale.

Apprezzare i suggerimenti di nessuno. Grazie in anticipo.

MODIFICA: Chiunque visualizzi questa domanda dovrebbe annotare la risposta seguente e i miei commenti finali su di esso. Ho spiegato come ho risolto questo problema, ma non ho ancora creato un post in stile "Q &".

+0

È sufficiente rilevare le eccezioni IOException e utilizzare un timeout di lettura. Non hai bisogno di tutto questo altro malarkey. – EJP

+0

L'ho già provato (nel caso non avessi letto il mio post ...) ed è un problema. Un'operazione di lettura che termina dopo un secondo causa un IO, che costringerebbe a disconnettere ... Ma cosa succede se non ho ricevuto dati ...? – DigitalJedi805

+0

Ho letto il tuo post. Non è "incostante", è soggetto a buffer di dati asincroni sia localmente che da remoto. Non si otterrà un'eccezione sulla prima scrittura su una connessione fallita, poiché non è stata ancora rilevata: la si otterrà in una scrittura successiva, dopo che TCP ha interrotto i tentativi. – EJP

risposta

12

Un'opzione è utilizzare i pacchetti keep-alive TCP. Li accendi con una chiamata a Socket.IOControl(). . Solo po 'fastidioso è che ci vuole un array di byte come input, in modo da avere per convertire i dati in un array di byte a passare in Ecco un esempio utilizzando un 10000ms mantenere vivo con un 1000 ms tentativi:

Socket socket; //Make a good socket before calling the rest of the code. 
int size = sizeof(UInt32); 
UInt32 on = 1; 
UInt32 keepAliveInterval = 10000; //Send a packet once every 10 seconds. 
UInt32 retryInterval = 1000; //If no response, resend every second. 
byte[] inArray = new byte[size * 3]; 
Array.Copy(BitConverter.GetBytes(on), 0, inArray, 0, size); 
Array.Copy(BitConverter.GetBytes(keepAliveInterval), 0, inArray, size, size); 
Array.Copy(BitConverter.GetBytes(retryInterval), 0, inArray, size * 2, size); 
socket.IOControl(IOControlCode.KeepAliveValues, inArray, null); 

Tenere i pacchetti vivi vengono inviati solo quando non si inviano altri dati, quindi ogni volta che si inviano dati, il timer 10000ms viene resettato.

+0

Impressionante, grazie Joel, sarò sicuro di fare un giro non appena avrò colpito il mio sistema Dev. – DigitalJedi805

+0

Hey Joel, quindi penso di avere l'idea qui, ma per favore correggimi se sbaglio; Il metodo IOControl consente di recapitare a tempo un pacchetto "KeepAlive" su un socket. Ho aggiunto (quasi parola per parola) il codice sopra a entrambi i miei costruttori SocketServer.Client e SocketClient. Ho ridotto il timer ad un secondo (dal momento che è il timeout sul mio 'letto' su entrambi i lati?) Ma il mio StreamReader.ReadLine (appena realizzato come sto digitando questo che questa non dovrebbe essere la mia strategia) non cattura mai alcun dato ... I devo dire che non sono sicuro del perché stiamo mettendo quello che stiamo mettendo nella serie; posso terminarlo in linea? – DigitalJedi805

+0

In realtà ho appena provato a eseguire la stessa cosa con una chiamata StreamReader.Read e non ho mai ricevuto nulla in nessuna direzione. Potrebbe essere che non capisco pienamente il concetto. – DigitalJedi805

Problemi correlati