2010-01-06 20 views
11

Parece que usar socket.Close() para un socket tcp, no cierra completamente el socket. En el siguiente ejemplo, intento conectarme a example.com en el puerto 9999, que no está abierto, y luego de un corto tiempo de espera, intento cerrar el socket.Socket.Close realmente no cierra socket tcp? (C#)

for (int i = 0; i < 200; i++) 
    { 
    Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
    sock.LingerState = new LingerOption(false, 0); 
    sock.BeginConnect("www.example.com", 9999, OnSocketConnected, sock); 
    System.Threading.Thread.Sleep(50); 
    sock.Close(); 
    } 

Pero cuando tomo un vistazo a netstat después del bucle se completa, me parece que hay muchas tomas entreabiertas:

TCP israel-xp:6506   www.example.com:9999 SYN_SENT 
    TCP israel-xp:6507   www.example.com:9999 SYN_SENT 
    TCP israel-xp:6508   www.example.com:9999 SYN_SENT 
    TCP israel-xp:6509   www.example.com:9999 SYN_SENT 

EDIT . Ok, faltaba algo de contexto. Estoy usando beginconnect porque espero que la conexión del socket falle (9999 no se abre), y en mi código real, llamo al socket.Close() una vez que se establece un temporizador. En OnSocketConnected llamo a EndConnect, que arroja una excepción (tratando de llamar a un método de un objeto eliminado). Mi objetivo es tener un tiempo de espera corto para la etapa de conexión de socket.

¿Alguna pista de lo que estoy haciendo mal? Gracias!

Respuesta

14

Cerrará la parte .NET del zócalo. Sin embargo, de acuerdo con la especificación TCP, el sistema operativo debe mantener abiertos los fragmentos de nivel inferior del socket durante un cierto período de tiempo para detectar la retransmisión, y similares. En este caso particular, es probable que se mantenga el socket por un tiempo para detectar una respuesta al paquete SYN enviado para que pueda responder de manera más sensata y no mezclar la respuesta con más paquetes enviados.

+2

que tenga sentido, pero que no establezca que la demora sea falsa, ¿debería resolverlo? – r0u1i

+0

oh, la demora no hace esto. Entonces, no hay realmente una manera de hacer que Windows termine el socket. – r0u1i

+1

de forma predeterminada se colocará en el estado FIN_WAIT durante 4 minutos antes de que Windows realmente lo cierre. Aún más interesante es que si vuelve a abrir la otra conexión con el mismo destino/puerto, Windows reutilizará las conexiones en FIN_WAIT que coincidan. – Jay

10

Está llamando *Begin*Connect - por lo que lo hace de forma asíncrona. Probablemente esté intentando cerrar el zócalo incluso antes de que esté conectado, de modo que cuando se conecta, permanece abierto.

Intente conectar sincrónicamente o cerrándolo en OnSocketConnected para que pueda ver el efecto de cerrar una toma realmente conectada.

+0

Ver mi edición. Uso BeginConnect a propósito, y mi código real espera un tiempo de espera antes de llamar a Close. Simplemente llamando a EndConnect en un socket (donde el puerto de destino no está abierto), solo tomará un * largo * tiempo para completarse. O, en otras palabras, quiero agotar el tiempo de espera de la etapa de conexión del socket después de X milisegundos (y no el número absurdamente alto de ventanas de milisegundos que tiene de forma predeterminada). – r0u1i

18

Por diseño, siempre debe llamar al Shutdown antes de cerrar el zócalo.

mySocket.Shutdown(SocketShutdown.Both); 
mySocket.Close(); 

Si lo hace, efectivamente desactiva enviar y recibir en el zócalo, por lo que no aceptará los datos de entrada después de que haya cerrado, aunque el sistema operativo todavía tiene el control del mismo.

Jon Skeet también tiene razón, ya que está abriendo la conexión de forma asíncrona, puede que se esté conectando mientras intenta cerrarla. Sin embargo, si llama al Shutdown, no permitirá que se reciba información mientras esté experimentando.

Editar: Sólo puede Shutdown un zócalo que ya está conectado, así que tenga esto en cuenta a medida que escribe su código.

+0

+1 para el comentario sobre la respuesta de Jon Skeet. :-) –

+0

ShutDown arroja un excpetion si el socket aún no está conectado, que es exactamente mi escenario. – r0u1i

+0

Luego debe usar OnSocketConnected para llamar a ShutDown y cerrarlo, o algo de esa naturaleza. –

0

Está inicializando un nuevo Socket en cada Loop ... con * .close() cierra el anterior y al principio está creando uno nuevo con los mismos parámetros que el Socket.

+0

sí. pero veo muchos más enchufes abiertos que solo uno. – r0u1i

Cuestiones relacionadas