2012-07-05 23 views
5

No se trata de cómo hacerlo, sino de si está mal lo que estoy haciendo. He leído que no es posible detectar si un socket se cierra inesperadamente (como matar el proceso servidor/cliente, desconectando el cable de red) mientras se esperan los datos (BeginReceive), sin el uso de temporizadores o mensajes enviados regularmente, etc. durante bastante tiempo he estado usando la siguiente configuración para hacer esto, y hasta ahora siempre ha funcionado perfectamente.Detección de desconexión de socket inesperada

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 
    } 
} 

Ahora, ya lo he leído no es posible sin más, me pregunto si hay algo mal con mi método. ¿Esta ahí? ¿O hay una diferencia entre matar procesos y tirar cables y similares?

Respuesta

12

Es perfectamente posible y está bien hacerlo. La idea general es:

Si EndReceive devuelve algo que no sea cero, tiene que procesar los datos entrantes.

Si EndReceive devuelve cero, el host remoto ha cerrado su extremo de la conexión. Eso significa que aún puede recibir los datos que envía si está programado para hacerlo, pero no puede enviar más de los suyos bajo ninguna circunstancia. Por lo general, cuando esto sucede también cerrará su extremo de la conexión, completando así un cierre ordenado, pero eso no es obligatorio.

Si EndReceive tiros, se ha producido una terminación anormal de la conexión (proceso matado, corte de cable de red, la potencia perdida, etc.).

Un par de puntos que hay que prestar atención a:

  1. EndReceive nunca puede volver a menos de cero (la prueba en su código es engañoso).
  2. Si se lanza puede lanzar otros tipos de excepción además de SocketException.
  3. Si devuelve cero, debe tener cuidado de dejar de llamar al BeginReceive; de lo contrario, comenzará un juego de ping-pong infinito y sin sentido entre BeginReceive y EndReceive (se mostrará en el uso de su CPU). Su código ya lo hace, por lo que no es necesario cambiar nada.
+0

+1 en particular porque me gusta cómo pones "si está programado para hacerlo". –

+2

+1 También me gustaría señalar que nunca se debe tener una declaración catch que capte todo a menos que se vuelva a lanzar. –

+1

@Alex No estoy de acuerdo con la prohibición de detectar todas las excepciones a menos que las vuelvas a lanzar. Tengo una clase de servidor TCP, que funciona muy parecido a la de aquí y no quiero una excepción aleatoria para terminar toda la aplicación de servidor. Es por eso que atrapo todas las excepciones y las paso a un manejador de eventos OnExceptionCaught, que debe estar conectado a alguna funcionalidad de registro, etc. – Algoman

Cuestiones relacionadas