Ir al contenido principal

Hace unos 18 meses escribí una entrada en el blog en la que hablaba de los cambios en el funcionamiento de «accept» en la versión 17.1 de OpenVOS. Lo que no señalé fue que estos cambios solo surten efecto si el código de la aplicación está basado en POSIX. En resumen, antes de la versión 17.1, STCP solo respondía a una solicitud de conexión del cliente si el código de la aplicación del servidor había llamado a la rutina «accept». Si el código no había llamado a «accept», la solicitud de conexión del cliente entraba en una cola, pero no recibía respuesta. Una vez que la aplicación llamaba a «accept», STCP enviaba una respuesta de conexión. Si el cliente seguía esperando, la conexión se completaba en ese momento. Si el cliente ya se había dado por vencido, respondía a la respuesta de conexión con un reinicio, STCP descartaba la conexión y «accept» se quedaba bloqueado (suponiendo que estuviera en modo de bloqueo) y esperaba otra conexión.

La figura 1 muestra este escenario; las líneas de texto alineadas a la izquierda son mensajes de estado de la aplicación del servidor, mientras que las líneas de packet_monitor (ligeramente modificadas) que aparecen sangradas son el resultado de la actividad del cliente. La aplicación (acceptTestnoPosix) se inicia y escucha en el puerto 12345, y una vez que está a la escucha, entra en suspensión durante 300 segundos. A continuación, el cliente establece una conexión con el puerto 12345 enviando un segmento TCP al puerto 12345 con la bandera Syn (S) activada. Lo intenta tres veces antes de darse por vencido. Tras 300 segundos, la aplicación se activa y llama a accept. La pila STCP responde al cliente con un segmento TCP con las banderas Syn y Ack (SA) activadas. Dado que el cliente ya no tiene un registro de la conexión, envía un Reset (R), por lo que STCP se bloquea en este punto. Si el socket estuviera en modo no bloqueante, accept habría devuelto un error EAGAIN.

acceptTestnoPosix 12345
Ejecutando acceptTestnoPosix 12345
En espera durante 300 segundos

  11:04:45.923 R TCP 164.152.77.50   164.152.77.217  11071  12345 S
  11:04:48.925 R TCP 164.152.77.50   164.152.77.217  11071  12345 S
  11:04:54.937 R TCP 164.152.77.50   164.152.77.217  11071  12345 S

Listo para aceptar una conexión en el puerto número 12345
  11:09:41.852 T TCP 164.152.77.217  164.152.77.50   12345  11071 SA 
  11:09:41.854 R TCP 164.152.77.50   164.152.77.217  11071  12345 R

Figura 1: acepta versiones anteriores a la 17.1 o versiones posteriores a la 17.1 que no sean POSIX

 

Si la aplicación está basada en POSIX, el proceso es diferente (Figura 2). STCP responde inmediatamente a la solicitud de conexión (S) (SA). A continuación, tras 300 segundos, la aplicación se activa, llama a «accept» y STCP devuelve el socket aceptado.

acceptTestwithPosix 12345
Ejecutando acceptTestnoPosix 12345
En espera durante 300 segundos

  10:58:43.962 R TCP 164.152.77.50   164.152.77.217  11024  12345 S
  10:58:43.964 T TCP 164.152.77.217  164.152.77.50   12345  11024 SA 
  10:58:43.964 R TCP 164.152.77.50   164.152.77.217  11024  12345 A

Listo para aceptar una conexión en el puerto número 12345
Conexión aceptada

Figura 2: aceptar publicaciones basadas en POSIX a partir de la versión 17.1

 

La diferencia de comportamiento puede ser crucial. Si el cliente espera una respuesta de la aplicación del servidor tras establecer una conexión, es posible que se agote el tiempo de espera y se cierre la conexión antes de que la aplicación llame realmente a la función «accept».

¿Cómo se crea una aplicación con POSIX? En primer lugar, la línea

#define _POSIX_C_SOURCE 200112L

debe ser la primera línea del código fuente de la aplicación. En segundo lugar, la ruta de la biblioteca

(master_disk)>sistema>biblioteca_de_objetos_posix

debe figurar en las rutas de la biblioteca de objetos después de las bibliotecas STCP y antes de la biblioteca C.

¿Cómo se puede saber si esto se ha hecho? Pues bien, puedes consultar las bibliotecas de objetos a las que se vinculó la aplicación mediante el comando `display_program_module -object_dirs`.

display_program_module acceptTestwithPosix -object_dirs      
     %azvos#m17_mas>SysAdmin>Noah_Davids>temp>acceptTestwithPosix.pm 

Mapa de directorios de objetos:

    11  directorios de búsqueda
     0  directorios que no se buscan
    11  directorios en total

   DTC  Ruta del directorio

     1  %azvos#m17_mas>SysAdmin>Noah_Davids>temp
     2  %azvos#m17_mas>system>stcp>object_library
     3  %azvos#m17_mas>system>stcp>object_library>socket
     4  %azvos#m17_mas>system>stcp>object_library>net
     5  %azvos#m17_mas>system>stcp>object_library>common
     6  %azvos#m17_mas>system>posix_object_library
     7  %azvos#m17_mas>system>c_object_library
     8  %azvos#m17_mas>sistema>biblioteca_de_objetos
     9  %azvos#m17_mas>opt>apache>lib
    10  %azvos#m17_mas>opt>openssl>lib
    11  %azvos#m17_mas>opt>mysql>lib>mysql

Pero esto no te indica si el #define forma parte del código fuente.

Si puedes ejecutar el código, puedes comprobar los indicadores del socket; un programa basado en POSIX tendrá activado el indicador SF_POSIX. Por ejemplo, tengo tres programas: acceptTestnoPosix, acceptTestwithPosix y acceptTestwithPosixPathOnly. Este último tenía el directorio >system>posix_object_library en las rutas de las bibliotecas, pero no incluía la definición #define en el código fuente. Ten en cuenta que esto se considera una combinación no válida. Solo la aplicación que estaba vinculada a la biblioteca POSIX y tenía la instrucción #define POSIX_SOURCE en el código creó un socket con el indicador SF_POSIX.

acceptTestnoPosix.pm 12345          
Ejecutando acceptTestnoPosix 12345
En espera durante 300 segundos
               como:  match posix; dump_stcbq -full -lport 12345       
               como:
acceptTestwithPosix.pm 12345\
Ejecutando acceptTestnoPosix 12345\
En espera durante 300 segundos\
               como:  match posix; dump_stcbq -full -lport 12345
                                                   SF_POSIX
               como:  
acceptTestwithPosixPathOnly.pm 12345
Ejecutando acceptTestnoPosix 12345
En espera durante 300 segundos
               como:  match posix; dump_stcbq -full -lport 12345
               como:

Existe una cuarta posibilidad: el #define se incluyó en el código fuente, pero no se utilizó la biblioteca posix_object_library. En este caso, la rutina de sockets devolverá un error.

acceptTestwithPosixDefineOnly 12345
Ejecutando acceptTestnoPosix 12345
acceptTestnoPosix: no se puede crear el socket de escucha: la aplicación se ha compilado  
+  de forma incorrecta: se debe buscar el tiempo de ejecución POSIX antes que el tiempo de ejecución C.

Todos los comandos y utilidades de STCP están desarrollados según POSIX, por lo que recomiendo encarecidamente que cualquier aplicación que desarrolles también utilice POSIX.