En C, entendí que si cerramos un socket, significa que el socket será destruido y puede reutilizarse más tarde.
¿Qué tal el apagado? La descripción dice que cierra la mitad de una conexión dúplex a ese zócalo. ¿Pero ese zócalo será destruido comoclose
llamada al sistema?
c
sockets
networking
tshepang
fuente
fuente
Respuestas:
Esto se explica en la guía de redes de Beej.
shutdown
Es una forma flexible de bloquear la comunicación en una o ambas direcciones. Cuando el segundo parámetro esSHUT_RDWR
, bloqueará tanto el envío como la recepción (comoclose
). Sin embargo,close
es la forma de destruir realmente un zócalo.Con
shutdown
, aún podrá recibir datos pendientes que el igual ya envió (gracias a Joey Adams por notar esto).fuente
shutdown
ambas direcciones pero noclose
es si hizoFILE
referencia al socket usandofdopen
. Siclose
utiliza el socket, a un archivo recién abierto se le puede asignar la misma fd, y el uso posterior deFILE
este leerá / escribirá en el lugar incorrecto, lo que podría ser muy malo. Si soloshutdown
, el uso posterior de laFILE
solo dará errores hasta quefclose
se llame.shutdown
: para señalar EOF al igual y aún poder recibir datos pendientes que el igual envió.Ninguna de las respuestas existentes le dice a la gente cómo
shutdown
yclose
funciona a nivel de protocolo TCP, por lo que vale la pena agregar esto.Una conexión TCP estándar se termina con una finalización de 4 vías:
Sin embargo, hay otra forma "emergente" de cerrar una conexión TCP:
En mi prueba con Wireshark, con las opciones de socket predeterminadas,
shutdown
envía un paquete FIN al otro extremo, pero es todo lo que hace. Hasta que la otra parte le envíe el paquete FIN, aún podrá recibir datos. Una vez que esto sucedió,Receive
obtendrá un resultado de tamaño 0. Entonces, si usted es el primero en cerrar "enviar", debe cerrar el socket una vez que haya terminado de recibir datos.Por otro lado, si llama
close
mientras la conexión aún está activa (el otro lado todavía está activo y es posible que también tenga datos no enviados en el búfer del sistema), se enviará un paquete RST al otro lado. Esto es bueno para los errores. Por ejemplo, si cree que la otra parte proporcionó datos incorrectos o se negó a proporcionar datos (¿ataque DOS?), Puede cerrar el socket de inmediato.Mi opinión sobre las reglas sería:
shutdown
antesclose
cuando sea posibleImplementaciones ideales para SHUT_RD y SHUT_WR
Lo siguiente no ha sido probado, confíe bajo su propio riesgo. Sin embargo, creo que esta es una forma razonable y práctica de hacer las cosas.
Si la pila TCP recibe un apagado solo con SHUT_RD, marcará esta conexión como no se esperan más datos. Las solicitudes pendientes y posteriores
read
(independientemente de la secuencia en la que se encuentren) se devolverán con un resultado de tamaño cero. Sin embargo, la conexión sigue activa y utilizable; por ejemplo, aún puede recibir datos OOB. Además, el sistema operativo eliminará cualquier dato que reciba para esta conexión. Pero eso es todo, no se enviarán paquetes al otro lado.Si la pila TCP recibe un apagado solo con SHUT_WR, marcará esta conexión ya que no se pueden enviar más datos. Se finalizarán todas las solicitudes de escritura pendientes, pero las solicitudes de escritura posteriores fallarán. Además, se enviará un paquete FIN a otro lado para informarles que no tenemos más datos para enviar.
fuente
shutdown()
la conexión y luego ya no está vivo. Aún tienes el descriptor de archivo. Todavía puederecv()
desde el búfer receptor. Y aún necesita llamarclose()
para disponer del descriptor de archivo.Hay algunas limitaciones con
close()
eso que se pueden evitar si se usa en sushutdown()
lugar.close()
terminará ambas direcciones en una conexión TCP. A veces desea decirle al otro punto final que ha terminado de enviar datos, pero aún desea recibir datos.close()
disminuye el recuento de referencias de descriptores (mantenido en la entrada de la tabla de archivos y cuenta el número de descriptores actualmente abiertos que se refieren a un archivo / socket) y no cierra el socket / archivo si el descriptor no es 0. Esto significa que si está bifurcando, la limpieza ocurre solo después de que el recuento de referencia cae a 0. Conshutdown()
uno se puede iniciar la secuencia de cierre TCP normal ignorando el recuento de referencia.Los parámetros son los siguientes:
int how
puede ser:SHUT_RD
o0
Más recibidos no están permitidosSHUT_WR
o No1
se permiten más envíosSHUT_RDWR
o No2
se permiten más envíos y recibosfuente
Esto puede ser específico de la plataforma, de alguna manera lo dudo, pero de todos modos, la mejor explicación que he visto está aquí en esta página de msdn donde explican sobre el apagado, las opciones de retraso, el cierre del socket y las secuencias generales de terminación de la conexión.
En resumen, use shutdown para enviar una secuencia de apagado a nivel TCP y use close para liberar los recursos utilizados por las estructuras de datos del socket en su proceso. Si no ha emitido una secuencia de apagado explícita para el momento en que llama al cierre, se iniciará una para usted.
fuente
También he tenido éxito con Linux usando
shutdown()
un pthread para forzar a otro pthread actualmente bloqueadoconnect()
a abortar temprano.Bajo otros sistemas operativos (OSX al menos), encontré que llamar
close()
era suficiente paraconnect()
fallar.fuente
"shutdown () en realidad no cierra el descriptor de archivo, solo cambia su usabilidad. Para liberar un descriptor de socket, debe usar close ()". 1
fuente
Cerca
Cuando haya terminado de usar un socket, simplemente puede cerrar su descriptor de archivo con close; Si todavía hay datos esperando ser transmitidos a través de la conexión, normalmente cierra intenta completar esta transmisión. Puede controlar este comportamiento utilizando la opción de socket SO_LINGER para especificar un período de tiempo de espera; ver Opciones de socket.
Apagar
También puede apagar solo la recepción o transmisión en una conexión llamando al apagado.
La función de apagado cierra la conexión del zócalo. Su argumento cómo especifica qué acción realizar: 0 Dejar de recibir datos para este socket. Si llegan más datos, rechazarlos. 1 Deje de intentar transmitir datos desde este socket. Descarte todos los datos que esperan ser enviados. Deje de buscar el reconocimiento de los datos ya enviados; no lo retransmita si se pierde. 2 Pare tanto la recepción como la transmisión.
El valor de retorno es 0 en caso de éxito y -1 en caso de error.
fuente
en mi prueba
close
enviará el paquete fin y destruirá fd inmediatamente cuando el socket no se comparta con otros procesosshutdown
SHUT_RD , el proceso aún puede recibir datos del socket, perorecv
devolverá 0 si el búfer TCP está vacío. Después de que el igual envíe más datos,recv
devolverá datos nuevamente.shutdown
SHUT_WR enviará un paquete de aletas para indicar que los envíos adicionales no están permitidos. el par puede recibir datos pero recibirá 0 si su búfer TCP está vacíoshutdown
SHUT_RDWR (igual que usar SHUT_RD y SHUT_WR ) enviará el primer paquete si el igual envía más datos.fuente
close()
envié RST en Linux en lugar de FIN.recv()
devolverá datos nuevamente' no es correcto. 2. El comportamiento si el igual envía más datos despuésSHUT_RD
depende de la plataforma.