2012-08-06 85 views
9

Estoy trabajando en una relación cliente/servidor que tiene la intención de enviar datos hacia adelante y hacia atrás durante un tiempo indeterminado.Cómo detectar un Desconexión de Socket en C#

El problema que estoy tratando de superar está en el lado del cliente, ya que no puedo encontrar la forma de detectar una desconexión.

He hecho un par de pases en soluciones de otras personas, que van desde la captura de excepciones de IO, hasta sondear el socket en los tres SelectModes. También intenté usar una combinación de encuesta, con un control en el campo 'Disponible' 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 
    } 
} 

En el lado del servidor, un intento de escribir un carácter 'vacío' (\ 0) obliga al cliente una excepción IO y el servidor puede detectar que el cliente se ha desconectado (concierto bastante fácil).

En el lado del cliente, la misma operación no produce ninguna excepción.

// 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 que creo que estoy teniendo en la detección de una falta de conexión a través de una encuesta, es que puedo justamente encontrar fácilmente una falsa sobre un SelectRead, si mi servidor aún no ha escrito nada nuevo al cliente ya el último control ... No estoy seguro de qué hacer aquí, he buscado cada opción para hacer esta detección que puedo encontrar y nada ha sido 100% para mí, y en última instancia, mi objetivo aquí es detectar un servidor (o conexión)) falla, informe al cliente, espere volver a conectarse, etc. Así que estoy seguro de que puede imaginarse que esta es una pieza integral.

Aprecie las sugerencias de cualquier persona. Gracias de antemano.

EDITAR: Cualquier persona que vea esta pregunta debe tener en cuenta la respuesta a continuación y mis comentarios FINALES al respecto. He explicado cómo superé este problema, pero todavía tengo que hacer una publicación de estilo 'Q & A'.

+0

Simplemente capture IOExceptions y use un tiempo de espera de lectura. No necesitas toda esta otra malarkey. – EJP

+0

Ya lo he intentado (en caso de que realmente no hayas leído mi publicación ...) y es impredecible. Una operación de lectura que se agota después de un segundo causa un IO, lo que forzaría una desconexión ... ¿Pero qué pasa si simplemente no he recibido datos ...? – DigitalJedi805

+0

Leí tu publicación. No es "al azar", está sujeto al almacenamiento en memoria de datos asincrónico tanto a nivel local como a distancia. No obtendrá una excepción en la primera escritura de una conexión fallida, ya que aún no se ha detectado: la obtendrá en una escritura subsiguiente, después de que TCP haya agotado el tiempo de los intentos de reintento. – EJP

Respuesta

12

Una opción es usar TCP keep alive packets. Puede activarlos con una llamada al Socket.IOControl(). . Sólo poco molesto es que se necesita una matriz de bytes como entrada, así que hay que convertir los datos a una matriz de bytes a transmitir en He aquí un ejemplo usando un 10000ms mantener viva con un 1000ms reintento:

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

Keep Los paquetes vivos se envían solo cuando no está enviando otros datos, por lo que cada vez que envía datos, se restablece el temporizador de 10000 ms.

+0

Impresionante, gracias Joel, me aseguraré de dar una vuelta tan pronto como llegue a mi sistema Dev. – DigitalJedi805

+0

Hola Joel, entonces creo que tengo la idea aquí, pero por favor corrígeme si estoy equivocado; El método IOControl coloca una entrega temporizada de un paquete 'KeepAlive' en un socket. Agregué (casi palabra por palabra) el código anterior a mis constructores SocketServer.Client y SocketClient. Reduje el temporizador a un segundo (¿ya que es el tiempo de espera en mi "lectura" en ambos lados?) Pero mi StreamReader.ReadLine (me acabo de dar cuenta de que estoy escribiendo esto, esta no debería ser mi estrategia) nunca capta ningún dato ... debo decir que no estoy seguro exactamente de por qué estamos poniendo lo que estamos poniendo en la matriz; puedo terminar la línea? – DigitalJedi805

+0

Realmente solo intenté ejecutar lo mismo con una llamada StreamReader.Read, y aún así no obtuve nada en ninguna dirección. Puede ser que no entiendo completamente el concepto. – DigitalJedi805

Cuestiones relacionadas