2009-12-17 1 views
5

Tengo un servidor que recibe solicitudes de conexión de los clientes. Este servidor hace uso del método asincrónico Socket.BeginReceive y Socket.EndReceive. El código es bastante similar al código encontrado here.C#: ¿Cómo finalizo un socket antes de que Socket.BeginReceive vuelva a llamar?

En mi caso, después de llamar al Socket.BeginReceive necesito un tiempo de espera tal que si el cliente se cuelga de la conexión pero no transmite ningún dato durante un período fijo de tiempo, debo terminar la conexión.

  • ¿Cómo hago para terminar la conexión en este escenario?
  • ¿Cuál es la mejor manera de codificar un temporizador ?

Respuesta

10

Simplemente llame al método Close() del zócalo. El método de devolución de llamada se ejecutará bastante rápido después de eso, obtendrá un ObjectDisposedException cuando llame al método EndReceive(). Prepárate para atrapar esa excepción.

Es probable que no desea bloquear el hilo que llama BeginReceive, se necesita un System.Threading.Timer o System.Timers.Timer para detectar el tiempo de espera. Su devolución de llamada debe llamar al Close(). Tenga cuidado con la inevitable condición de carrera que esto causa, la devolución de llamada del temporizador se ejecutará si la respuesta se recibió un microsegundo antes de que el temporizador expirara. Cerrará el socket, a pesar de que obtuvo una buena respuesta. La próxima llamada al BeginReceive() fallará inmediatamente.

+0

¿Quiere decir que el método de devolución de llamada seguirá ejecutándose después de llamar al método de cierre del socket? – Lopper

+1

Si un BeginReceive() está pendiente: sí. * Siempre * tiene que estar emparejado con una llamada EndReceive(). No puede evitar la devolución de llamada. –

+0

Gracias nobugz :) – Lopper

0

Según el artículo de MSDN en Socket.BeginReceive Afirma

Para cancelar una BeginReceive pendiente, llamar al método Close.

+0

Y para citar la documentación del método Close: "Para los protocolos orientados a la conexión, se recomienda llamar a Shutdown antes de llamar al método Close. Esto asegura que todos los datos se envían y reciben en el socket conectado antes de que sea cerrado." –

0

Puede recibir algunos datos iniciales de forma asincrónica y luego realizar una recepción sincrónica para el resto de los datos y confiar en ReceiveTimeout para desconectar el cliente. Puede usar Socket.Close para desconectar el cliente por la fuerza.

Pero si desea utilizar solo la recepción asincrónica, puede usar temporizadores y restablecerlos en EndReceive. Si transcurre, puede desconectar el cliente con fuerza.

Pero creo que el primer enfoque es mejor.

7

Sé que este hilo es bastante viejo, pero acabo de encontrar el mismo problema y no estaba satisfecho con la respuesta dada aquí (o en cualquier otro lugar por ese asunto).

Una mejor solución para cancelar un Socket.BeginReceive pendiente es llamar al Socket.Shutdown y no al Socket.Close. De esta forma, el controlador asynch se genera "normalmente", y una llamada al Socket.EndReceive devuelve 0 -> en lugar de arrojar una esperada excepción esperada. Siempre debe tener un

if (Socket.EndReceive() > 0) { 
    //Do something 
} else { 
    //Socket has been shut down (either by you or the other end of the connection) 
    //Now it's "safe" to call Socket.Close 
    Socket.Close(); 
} 

por lo que ni siquiera es necesario para ajustar su asynch-devolución de llamada para manejar la anulación manual.

Cuestiones relacionadas