cerrar vs apagar socket?


En C, entendí que si cerramos un socket, significa que el socket será destruido y puede ser reutilizado 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 socket será destruido como close llamada al sistema?

Author: Tshepang, 2010-11-12

8 answers

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 es SHUT_RDWR, bloqueará tanto el envío como la recepción (como close). Sin embargo, close es la forma de destruir un socket.

Con shutdown, todavía podrá recibir datos pendientes que el par ya envió (gracias a Joey Adams por anotar esto).

 154
Author: Matthew Flaschen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-01 13:06:32

Ninguna de las respuestas existentes le dice a la gente cómo shutdown y close funciona a nivel de protocolo TCP, por lo que vale la pena agregar esto.

Una conexión TCP estándar se termina al finalizar en 4 direcciones:

  1. Una vez que un participante no tiene más datos para enviar, envía un paquete FIN al otro{[14]]}
  2. La otra parte devuelve un ACK para la FIN.
  3. Cuando la otra parte también terminó la transferencia de datos, envía otro paquete FIN
  4. El participante inicial devuelve un ACK y finaliza la transferencia.

Sin embargo, hay otra forma" emergente " de cerrar una conexión TCP:

  1. Un participante envía un paquete RST y abandona la conexión
  2. El otro lado recibe un RST y luego abandona la conexión también

En mi prueba con Wireshark, con 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, usted todavía puede recibir datos. Una vez que esto sucedió, su Receive obtendrá un resultado de tamaño 0. Así que si usted es el primero en apagar "enviar", debe cerrar el socket una vez que haya terminado de recibir datos.

Por otro lado, si llama a close mientras la conexión todavía está activa (el otro lado todavía está activo y puede tener datos no enviados en el búfer del sistema también), se enviará un paquete RST al otro lado. Esto es bueno para errores. Por ejemplo, si cree que la otra parte proporcionó datos incorrectos o se negó a proporcionar datos (¿ataque DOS?), puede cerrar el zócalo de inmediato.

Mi opinión sobre las reglas sería:

  1. Considere shutdown antes de close cuando sea posible
  2. Si terminó de recibir (datos de tamaño 0 recibidos) antes de que decidiera apagar, cierre la conexión después de que el último envío (si lo hubiera) haya terminado.
  3. Si desea cerrar la conexión normalmente, apague la conexión (con SHUT_WR, y si no le importa recibir datos después de este punto, con SHUT_RD como bien), y espere hasta que reciba un tamaño de datos 0, y luego cierre el socket.
  4. En cualquier caso, si se produce cualquier otro error (por ejemplo, tiempo de espera), simplemente cierre el socket.

Implementaciones ideales para SHUT_RD y SHUT_WR

Lo siguiente no ha sido probado, confíe en 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. Cualquier solicitud pendiente y posterior read (independientemente del hilo en el que se encuentren) se devolverá con un resultado de tamaño cero. Sin embargo, la conexión sigue activa y utilizable you todavía puede recibir datos OOB, por ejemplo. 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 como no se pueden obtener más datos enviado. Todas las solicitudes de escritura pendientes se completarán, pero las solicitudes de escritura posteriores fallarán. Además, un paquete FIN será enviado a otro lado para informarles que no tenemos más datos para enviar.

 103
Author: Earth Engine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-29 23:29:19

Hay algunas limitaciones con close() que se pueden evitar si se usa shutdown() en su lugar.

close() terminará ambas direcciones en una conexión TCP. A veces desea decirle al otro extremo que ha terminado con el envío de datos, pero aún así desea recibir datos.

close() decrementa el recuento de referencia 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 / file si el descriptor no es 0. Esto significa que si está bifurcando, la limpieza ocurre solo después de que el recuento de referencia caiga a 0. Con shutdown() se puede iniciar una secuencia de cierre TCP normal ignorando el recuento de referencias.

Los parámetros son los siguientes:

int shutdown(int s, int how); // s is socket descriptor

int how puede ser:

SHUT_RD o 0 Otras recepciones no están permitidas

SHUT_WR o 1 Los envíos no están permitidos

SHUT_RDWR o 2 Otros envíos y recepciones no están permitidos

 31
Author: Milan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-17 00:50:05

Esto puede ser específico de la plataforma, de alguna manera lo dudo, pero de todos modos, la mejor explicación que he visto es aquí en esta página de msdn donde explican sobre el apagado, las opciones de permanencia, el cierre de sockets y las secuencias de terminación de conexión en general.

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 de sockets en su proceso. Si no ha emitido una secuencia de apagado explícita en el momento de llamar cerrar entonces se inicia uno para ti.

 14
Author: Len Holgate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-18 08:33:34

También he tenido éxito bajo Linux usando shutdown() de un pthread para forzar a otro pthread actualmente bloqueado en connect() a abortar antes.

Bajo otros sistemas operativos (al menos OSX), encontré que llamar a close() era suficiente para que connect() fallara.

 6
Author: Toby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-15 08:56:33

"shutdown() en realidad no cierra el descriptor de archivo-solo cambia su usabilidad. Para liberar un descriptor de socket, necesitas usar close()."1

 6
Author: sand_storm_of_code.txt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-12 01:22:43

Cerrar

Cuando haya terminado de usar un socket, simplemente puede cerrar su descriptor de archivo con close; Si todavía hay datos esperando a ser transmitidos a través de la conexión, normalmente close intenta completar esta transmisión. Puede controlar este comportamiento utilizando la opción SO_LINGER socket para especificar un período de tiempo de espera; consulte Opciones de socket.

ShutDown

También puede apagar solo la recepción o transmisión en una conexión llamando apagado.

La función shutdown apaga la conexión del socket. Su argumento how especifica qué acción realizar: 0 Deje de recibir datos para este socket. Si llegan más datos, recházalos. 1 Deje de intentar transmitir datos desde este socket. Deseche cualquier dato que esté esperando ser enviado. Deje de buscar el acuse de recibo de los datos ya enviados; no lo retransmita si se pierde. 2 Detenga tanto la recepción como la transmisión.

El valor devuelto es 0 en caso de éxito y -1 en caso de error.

 1
Author: Neha Agrawal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-21 11:57:41

En mi prueba.

close enviará el paquete fin y destruirá fd inmediatamente cuando el socket no se comparta con otros procesos

shutdown SHUT_RD , el proceso todavía puede recv datos desde el socket, pero recv devolverá 0 si el búfer TCP está vacío.Después de que el par envíe más datos, recv devolverá los datos de nuevo.

shutdown SHUT_WR enviará un paquete fin para indicar que los envíos Posteriores no están permitidos. el par puede recv datos pero recv 0 si su búfer TCP es vacío

shutdown SHUT_RDWR (igual a usar ambos SHUT_RD y SHUT_WR) enviará el paquete rst si el par envía más datos.

 0
Author: simpx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-17 06:06:28