Pregunta

Con suerte alguien nos puede ayudar ya que estamos llegando hasta la investigación puede ir!

Tenemos un simple servidor de socket asíncrono escrito en C # que acepta conexiones desde una aplicación Web ASP.NET, se envía un mensaje, realiza algún procesamiento (por lo general en contra de una base de datos, pero otros sistemas también) y luego envía una respuesta de vuelta al cliente. El cliente es el encargado de cerrar la conexión.

Hemos tenido problemas en donde si el sistema está bajo carga pesada durante un largo período de tiempo (días) por lo general, los zócalos CLOSE_WAIT se acumulan en el cuadro Servidor (netstat) hasta el punto de que el proceso no aceptará realizar ninguna otra conexión. En ese momento tenemos que rebotar el proceso y fuera de él se ejecuta de nuevo.

Hemos intentado ejecutar algunas pruebas de carga de nuestra aplicación ASP.NET para intentar reproducir el problema (porque inferir una cierta edición del código no era posible). Creemos que hemos logrado esto y terminamos con una WireShark paquete de trazas de la cuestión que se manifiesta como una SocketException en los registros del servidor socket:

  

System.Net.Sockets.SocketException: Una conexión existente forzosamente fue cerrada por el host remoto   en System.Net.Sockets.Socket.BeginSend (byte [] buffer, Int32 compensado, tamaño Int32, SocketFlags SocketFlags, AsyncCallback de devolución de llamada, el estado Object)

He intentado reproducir el problema del rastreo de paquete como un único proceso de roscado directamente hablando con el servidor de socket (utilizando el mismo código de la aplicación ASP.NET hace) y no puedo.

Alguien tiene alguna sugerencia de próximos cosas para probar, comprobar si hay o cosas obvias que pueden estar haciendo mal?

¿Fue útil?

Solución

Observa el diagrama

http://en.wikipedia.org/wiki/File:Tcp_state_diagram_fixed.svg

Su cliente cierra la conexión llamando a close (), que envió FIN al socket del servidor, que ACKed la aleta y el estado de la que ahora ha cambiado a CLOSE_WAIT, y se mantiene de esa manera a menos que el servidor emite close () llamada en esa socket.

Su programa de servidor tiene que detectar si el cliente haya abortado la conexión y cierre () inmediatamente para liberar el puerto. ¿Cómo? Consulte a leer (). Tras la lectura de fin de archivo (es decir, se recibe FIN), se devuelve cero.

Otros consejos

Si su servidor está acumulando tomas CLOSE_WAIT entonces no es el cierre de su toma cuando se complete la conexión. Si se echa un vistazo en el diagrama de estado en el comentario posterior a Chris' verá que las transiciones CLOSE_WAIT a LAST_ACK una vez que se cierra el conector y el FIN ha sido enviado.

Usted dice que es complejo determinar dónde hacer esto debido a la naturaleza asíncrona? Esto no debería ser un problema, debe cerrar la toma si la devolución de llamada desde su recv devuelve 0 bytes (suponiendo que tiene nada más que hacer una vez que su cliente cierra su lado de la conexión). Si usted no necesita preocuparse por seguir enviando a continuación, hacer un apagado (recv) aquí y tome nota de que su cliente ha cerrado, una vez que haya terminado el envío de hacer un apagado (enviar) y un cierre.

Se le puede emitir una nueva lectura en la devolución de llamada desde la lectura que devuelve 0, que indica que el cliente ha cerrado y esto puede estar causando problemas?

  

El cliente es el encargado de cerrar la conexión.

Tanto el cliente como el servidor deben cerrar y cierre el zócalo. O bien el cliente no está terminando el cierre (poco probable - ya que tendría es administrado finalizador) o el servidor no está cerrando la toma (probable)

.
using (Socket s = new Socket(/* */)) {
  /* Do stuff */
  s.Shutdown(SocketShutdown.Both);
  s.Close();
}

No debe estar dejando la responsabilidad de cerrar los sockets TCP sólo hasta el cliente. ¿Qué ocurre si el proceso cliente / máquina se cuelga?

Lo ideal es tener un tiempo de espera en su lugar de modo que si no hay tráfico se recibe en un conector conectado después de una cierta cantidad de tiempo, entonces se cierra por el servidor.

No importa lo que sucede cuando todas las operaciones en el zócalo ha terminado por el cliente, y no se necesita hacer ninguna operación más leídos en el zócalo, el cliente debe emitir una orden de cierre.

Esta emisión de orden de cierre, simplemente le dice al oyente (el servidor) que la conexión tiene que ser cerrado.

En palabras simples, cuando el servidor de nuevo emite un comando de lectura (listener.read () o listener.beginread (...) en modo asíncrono), la lectura volverá a 0 bytes leídos, esto en sí mismo indica que la socket necesita ser cerrado por el oyente como cualquier otra operación en el zócalo ha dejado por el cliente.

CLOSE_WAIT de están destinados a colgar alrededor por un tiempo después de una toma de corriente está cerrado, para prevenir la re-utilizando el mismo número de socket y recibir paquetes desde la antigua conexión. Esto sólo le dará pena si usted está abriendo y cerrando una serie de tomas huuuuge muy rápido.

EDITAR -. Debe ser TIME_WAIT, no CLOSE_WAIT anterior

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top