2009-09-02 18 views
8

Estoy desarrollando un servidor en C# que puede aceptar solo un cliente y necesito saber cuándo este cliente está desconectado para poder aceptar otras solicitudes de conexión.¿La mejor práctica para detectar una desconexión del cliente en .NET?

Estoy usando un primer Socket que escucha continuamente la solicitud de conexión con Socket.BeginAccept y acepta o rechaza clientes. Cuando se acepta un cliente, se utiliza el nuevo Socket que se devuelve por Socket.EndAccept para la comunicación entre el cliente y el servidor. Luego, el servidor espera los comandos del cliente con Socket.Begin/EndReceive y envía respuestas. El servidor utiliza un protocolo similar a Telnet, lo que significa que cada comando y cada línea de respuesta debe finalizar con \r\n.

Para detectar si el cliente ha sido desconectado, he instalado un temporizador que envía cada 500 ms un mensaje vacío ("\r\n") al cliente. Si el cliente está desconectado, el Socket lanza una excepción. Esta excepción es capturada por el servidor que cierra la sesión actual y acepta una nueva conexión. Esta solución es robusta pero implica tráfico innecesario en la red y debe ser manejada correctamente por el cliente, que debe filtrar los mensajes falsos antes de obtener una respuesta real.

He intentado enviar un búfer vacío (Socket.Send(new byte[1], 0, 0)), pero parece que no funciona en la dirección server-> client.

Otra solución podría ser manejar el caso en el que Socket.EndReceive devuelve 0 bytes. Funciona bien para el caso de una desconexión que ocurre durante el tiempo "inactivo". Pero si el cliente se desconecta durante la transferencia de un mensaje, el servidor no siempre lo ve y espera indefinidamente.

Ya he visto varios hilos y preguntas sobre este problema, pero nunca he visto una buena solución.

Entonces mi pregunta es: ¿cuál es la mejor manera de detectar una desconexión en .Net?

Respuesta

4

La única otra opción es si TCP es hacer que TCP envíe un keep-alive de vez en cuando, que sigue sondeando, como lo que está haciendo ahora, pero manejado en la capa TCP para que no tenga protocolo no necesito saber

No hay forma de evitar el sondeo, sin embargo, ya que sin enviar algo al otro cliente y obtener una respuesta no tiene manera de saber si todavía está conectado o no.

Mantener vivo también puede ser necesario de todos modos cuando se comunica a través de la inspección de paquetes con estado, como NAPT estándar para evitar que el servidor remoto cierre la sesión debido a la actividad.

+0

OK, he agregado que permite KeepAlive para mi zócalo. Pero, ¿qué se supone que debo esperar ahora? No sucede nada cuando el cliente rompe la conexión ... Esperaba recibir una excepción en alguna parte ... ¿Debo leer o escribir algo periódicamente? – cedrou

+1

¿Pensé que estabas usando Begin/EndReceive? Si es así, el BeginReceive debe ejecutar la devolución de llamada y cuando llame a EndReceive para obtener el resultado, se debe hacer una excepción, eso o un final de la transmisión de 0 byte. –

+0

OK, tengo una excepción ahora ... Gracias – cedrou

3

Puede utilizar el siguiente método para determinar si un cliente todavía está conectado. Este

public static bool IsConnected(this TcpClient client) 
{ 
    try 
    { 
     bool connected = !(client.Client.Poll(1, SelectMode.SelectRead) && client.Client.Available == 0); 

     return connected; 
    } 
    catch 
    { 
     return false; 
    } 
} 

este answer es para el zócalo de la prueba, que es como yo tengo mi fragmento de código.

+2

Este método funciona bien si el cliente ha cerrado explícitamente la conexión, pero no si la conexión se ha roto (cable desenchufado, por ejemplo). – cedrou

+0

que es donde entra en juego keep alive, el sistema operativo y el protocolo TCP manejarán los mensajes periódicos al cliente para ver si están activos, y al sondear el socket se verificará el estado local. Si un mantener vivo falla el socket debe informar que ya no está conectado. –

+0

Aunque al utilizar la función de inicio asincrónico/final, no es necesario realizar la votación, ya que debe recibir una devolución de llamada con el error cuando el socket no se mantiene activo. –

0

¿Tiene control sobre el cliente? Si es así, ¿no puedes hacer que el cliente envíe un paquete especial al servidor diciendo que se está desconectando, y luego desconectar el zócalo?

¿Está tratando de detectar el caso de que el cliente realmente se ha desconectado (utilizando Socket.Shutdown(), o Socket.Close()) o si el cliente está inactivo durante un tiempo enorme, y por lo tanto necesita ser expulsado?

En cualquier caso, haga que el cliente envíe un mensaje periódico (tal como lo hizo) al servidor.El servidor puede realizar un seguimiento de los últimos latidos, y si el cliente pierde más de 3 latidos, puede desconectar al cliente. sí, implica datos adicionales, pero eso no está mal en el gran esquema de cosas. Si lo sintoniza para que envíe el latido del corazón en un período suficientemente bueno, para que tenga la ventaja de saber si el cliente está vivo, y no pasar demasiado tiempo entre latidos del corazón, podría tener un sistema muy bueno.

Cuestiones relacionadas