Cierre correcto, opciones persistentes y cierre de socket

El siguiente material se proporciona como aclaración para el asunto de apagar las conexiones de socket que cierran los sockets. Es importante distinguir la diferencia entre apagar una conexión de socket y cerrar un socket.

Apagar una conexión de socket implica un intercambio de mensajes de protocolo entre los dos puntos de conexión, a partir de entonces denominado secuencia de apagado. Se definen dos clases generales de secuencias de apagado: correcta y abortiva (también denominadas duras). En una secuencia de apagado correcta, los datos que se han puesto en cola, pero que aún no se pueden transmitir se pueden enviar antes de cerrar la conexión. En un apagado abortivo, se pierden los datos no enviados. La aparición de una secuencia de apagado (correcta o abortiva) también se puede usar para proporcionar una indicación de FD_CLOSE a las aplicaciones asociadas que indican que un apagado está en curso.

Cerrar un socket, por otro lado, hace que el controlador de socket se desasigne para que la aplicación ya no pueda hacer referencia ni usar el socket de ninguna manera.

En Windows Sockets, tanto la función shutdown como la función WSASendDisconnect se pueden usar para iniciar una secuencia de apagado, mientras que la función closesocket se usa para desasignar los identificadores de socket y liberar los recursos asociados. Sin embargo, surge cierta cantidad de confusión del hecho de que la función closesocket provoca implícitamente que se produzca una secuencia de apagado si aún no se ha producido. De hecho, se ha convertido en una práctica de programación bastante común para confiar en esta característica y usar closesocket para iniciar la secuencia de apagado y desasignar el controlador de socket.

Para facilitar este uso, la interfaz de sockets proporciona controles a través del mecanismo de opción de socket que permite al programador indicar si la secuencia de apagado implícita debe ser correcta o abortiva, y también si la función closesocket debe permanecer (que no se completa inmediatamente) para permitir que se complete una secuencia de apagado correcta. Estas diferencias importantes y las ramificaciones del uso de closesocket de esta manera aún no se comprenden ampliamente.

Al establecer los valores adecuados para las opciones de socket SO_LINGER y SO_DONTLINGER, se pueden obtener los siguientes tipos de comportamiento con la función closesocket :

  • Secuencia de apagado abortivo, retorno inmediato de closesocket.
  • Apagado correcto, retrasando la devolución hasta que se completa la secuencia de apagado o transcurrido un intervalo de tiempo especificado. Si el intervalo de tiempo expira antes de que finalice la secuencia de apagado correcto, se produce una secuencia de apagado anulativo y se devuelve closesocket .
  • Apagado correcto, retorno inmediato, lo que permite que la secuencia de apagado se complete en segundo plano. Aunque este es el comportamiento predeterminado, la aplicación no tiene forma de saber cuándo (o si) la secuencia de apagado correcta se completa realmente.

El uso de las opciones de socket SO_LINGER y SO_DONTLINGER y la estructura de persistencia asociada se describe con más detalle en las secciones de referencia sobre SOL_SOCKET Opciones de socket y la estructura persistente .

Una técnica que se puede usar para minimizar la posibilidad de que se produzcan problemas durante la desmontaje de la conexión es evitar depender de un apagado implícito iniciado por Closesocket. En su lugar, use una de las dos funciones de apagado explícitas, shutdown o WSASendDisconnect. Esto, a su vez, hace que la aplicación del mismo nivel reciba una indicación FD_CLOSE que indica que se han recibido todos los datos pendientes. Para ilustrar esto, en la tabla siguiente se muestran las funciones que invocarían los componentes de cliente y servidor de una aplicación, donde el cliente es responsable de iniciar un apagado correcto.

En el cliente En el servidor
(1) Invoca apagados, SD_SEND) para indicar el final de la sesión y ese cliente no tiene más datos que enviar.
(2) Recibe FD_CLOSE, lo que indica un apagado correcto en curso y que se han recibido todos los datos.
(3) Envía los datos de respuesta restantes.
(solo significación de tiempo local) Obtiene FD_READ y llama a recv para obtener los datos de respuesta enviados por el servidor . (4) Invoca apagados, SD_SEND) para indicar que el servidor no tiene más datos que enviar.
(5) Recibe FD_CLOSE indicación. (solo significación de tiempo local) Invoca closesocket .
(6) Invoca closesocket.