Ir al contenido principal

En este post deseo discutir un error de codificación común que puede resultar en que un módulo se quede sin o por lo menos agote seriamente el número disponible de clones de dispositivos stcp para su uso en la creación de sockets TCP.

Cada llamada a la función de enchufe hace que el STCP cree un nuevo clon del dispositivo stcp. El número máximo de clones que se pueden crear está controlado por el campo clone_limit en la entrada devices.tin.

/ =nombre stcp.m17
     =modulo_nombre_de_módulo m17
     = tipo_de_dispositivo corrientes
     =nombre_de_lista_de_acceso stcp_access
     =streams_driver stcp
     =clone_limit 5120
     =comentario Proporciona TCP API

Puedes ver cuántos clones están actualmente en uso volcando la estructura del dispositivo en analyze_system y mirando el valor de clone_count. Si clone_count es igual a clone_limit entonces las llamadas a la función socket devolverán un e$clone_limit_excedido: Error de "El límite de clonación del dispositivo ha sido excedido".

as: match clone; dump_dvt -nombre stcp.m17
límite_de_clonación: 5120
clone_count:       42
clonado_de: -27271
remote_clone_limit: 0

En general, la llamada del enchufe que crea el dispositivo de clonación es seguida por una Conecta llamar o atar y escuchar llamadas. En ese momento se puede ver una entrada correspondiente cuando se ejecuta el "comando netstat".

netstat -numérico -all_sockets
Conexiones activas (incluyendo servidores)
Proto Recv-Q Send-Q Dirección local Dirección en el extranjero (estado)
tcp 0 0 172.16.124.217:23 192.168.109.22:50038 ESTABLECIDO
tcp 0 0 172.16.124.217:22 172.16.124.24:54987 ESTABLECIDO
tcp 0 0 10.20.1.1:37 10.20.1.26:1528 TIME_WAIT
tcp 0 0 10.20.1.1:37 10.20.1.27:1579 TIME_WAIT
tcp 0 0 172.16.124.217:61780 192.168.109.22:23 ESTABLECIDO
tcp 0 0 172.16.124.217:22 172.16.124.50:17421 ESTABLECIDO
tcp 0 0 172.16.124.217:22 172.16.124.50:17658 ESTABLECIDO
tcp 0 0 *:23 *:* ESCUCHA
tcp 0 0 *:6666 *:* ESCUCHA
tcp 0 0 *:21 *:* ESCUCHA
tcp 0 0 *:3000 *:* ESCUCHA
tcp 0 0 *:7 *:* ESCUCHA
tcp 0 0 *:9 *:* ESCUCHA
tcp 0 0 *:13 *:* ESCUCHA
tcp 0 0 *:19 *:* ESCUCHA
tcp 0 0 *:37 *:* ESCUCHA
tcp 0 0 *:901 *:* ESCUCHA
tcp 0 0 *:1414 *:* ESCUCHA
tcp 0 0 *:81 *:* ESCUCHA
tcp 0 0 10.20.1.1:37 10.20.1.9:3633 TIME_WAIT
tcp 0 50 10.10.1.1:52653 10.10.1.200:3001 ESTABLECIDO
tcp 0 0 10.10.1.1:52624 10.10.1.200:3001 FIN_WAIT_1
tcp 0 0 10.20.1.1:61704 10.20.1.3:48879 ESTABLECIDO
tcp 0 0 *:3001 *:* ESCUCHA
tcp 0 0 *:3002 *:* ESCUCHA
tcp 0 0 *:3003 *:* ESCUCHA
tcp 0 0 *:4000 *:* ESCUCHA
tcp 0 0 172.16.124.217:4000 172.16.124.78:1024 ESTABLECIDO
tcp 0 0 172.16.124.217:4000 172.16.124.227:1025 ESTABLECIDO
tcp 0 0 *:4001 *:* ESCUCHA
tcp 0 0 *:4002 *:* ESCUCHA
tcp 0 0 *:4003 *:* ESCUCHA
tcp 0 0 *:4004 *:* ESCUCHA
tcp 0 0 *:22 *:* ESCUCHA
tcp 0 0 *:4005 *:* ESCUCHA
tcp 0 0 *:4006 *:* ESCUCHA
tcp 0 0 172.16.124.217:4006 172.16.124.203:49231 ESTABLECIDO
tcp 0 0 *:4007 *:* ESCUCHA
tcp 0 0 *:4008 *:* ESCUCHA
tcp 0 0 *:4009 *:* ESCUCHA
tcp 0 0 172.16.124.217:4008 172.16.124.203:49262 ESTABLECIDO
tcp 0 0 *:4010 *:* ESCUCHA
tcp 0 0 *:4011 *:* ESCUCHA
tcp 0 0 *:4012 *:* ESCUCHA
tcp 0 0 *:4013 *:* ESCUCHA
tcp 0 0 *:4014 *:* ESCUCHA
tcp 0 0 *:4015 *:* ESCUCHA
tcp 0 0 *:80 *:* ESCUCHA
tcp 0 0 *:9182 *:* ESCUCHA
tcp 0 0 *:445 *:* ESCUCHA
tcp 0 0 *:139 *:* ESCUCHA
tcp 0 0 10.20.1.1:53495 10.20.1.9:48879 ESTABLECIDO
tcp 0 0 10.20.1.1:61703 10.20.1.3:48879 ESTABLECIDO
tcp 0 0 10.20.1.1:61707 10.20.1.3:48879 ESTABLECIDO
tcp 0 0 10.20.1.1:61705 10.20.1.9:48879 ESTABLECIDO
tcp 0 0 10.20.1.1:61709 10.20.1.9:48879 ESTABLECIDO
tcp 0 0 10.20.1.1:61710 10.20.1.9:48879 ESTABLECIDO
tcp 0 0 172.16.124.217:61789 172.16.124.203:4000 ESTABLECIDO
tcp 0 400 172.16.124.217:22 172.16.124.50:17674 ESTABLECIDO

Si cuentas el número de líneas verás más de 42, eso es porque no todas las entradas mostradas por netstat utilizan un clon de un dispositivo stcp. Por ejemplo, las conexiones OSL y las conexiones X25_cpc usadas con el NIO. Echa un vistazo a socket_count.cm para más detalles.

Si se realiza una llamada a un socket sin un connect o bind o el bind falla, se puede crear el problema opuesto, el valor de clone_count es mayor que el número de entradas que muestra netstat.

as: clon del partido; dump_dvt -nombre stcp.m17
límite_de_clonación: 5120
clon_count:       4131
clonado_de: -23179
remote_clone_limit: 0
como:

No estoy incluyendo la salida de netstat de nuevo, pero confía en mí que no ha cambiado desde el ejemplo anterior.

Esta situación, un extra (4131 - 42) y aparentemente no se ha encontrado, los clones del dispositivo STCP fue creado por el siguiente fragmento de código. El código llama a la función de encaje seguida de la función de unión. Si el "bind" falla, hace un bucle. Muchas aplicaciones añadirían un temporizador para esperar 1, 60, o 300 segundos e intentarlo de nuevo, que sólo retrasa lo inevitable, asumiendo por supuesto que la condición que causa el error no desaparece.

tryAgain = 1;
while (tryAgain)
  {
  if ((socks0 = socket (AF_INET, SOCK_STREAM, 0)) < 0)
     {
     if (debugFlag)
        perror ("badService: can't create listening socket");
     }
  else {
/* build a sockaddr structure holding the address we will bind to.
   The IP address is INADDR_ANY meaning we will listen on all active
   IP addresses */

     bzero ( (char *) &serv_addr, sizeof (serv_addr));
     serv_addr.sin_family        = AF_INET;
     serv_addr.sin_addr.s_addr   = htonl (INADDR_ANY);
     serv_addr.sin_port          = htons (portNumber);

/* now bind to the address and port */
     if (bind (socks0, (struct sockaddr *) &serv_addr,
                                      sizeof (serv_addr)) < 0)
        {
        if (debugFlag)
           perror ("badService: can't bind address, trying again");
        }
     else
        tryAgain = 0;
     }
   }

El error más común es que otro proceso ya se ha unido al puerto solicitado. Independientemente de la razón del error, la solución es cerrar el zócalo después de informar del error de enlace.

tryAgain = 1;
while (tryAgain)
  {
  if ((socks0 = socket (AF_INET, SOCK_STREAM, 0)) < 0)
     {
     if (debugFlag)
        perror ("goodService: can't create listening socket");
     }
  else {
/* build a sockaddr structure holding the address we will bind to.
   The IP address is INADDR_ANY meaning we will listen on all active
   IP addresses */

     bzero ( (char *) &serv_addr, sizeof (serv_addr));
     serv_addr.sin_family        = AF_INET;
     serv_addr.sin_addr.s_addr   = htonl (INADDR_ANY);
     serv_addr.sin_port          = htons (portNumber);

/* now bind to the address and port */
     if (bind (socks0, (struct sockaddr *) &serv_addr,
                                      sizeof (serv_addr)) < 0)
        {
        if (debugFlag)
           perror ("goodService: can't bind address, trying again");
        if (close (socks0) < 0)
           if (debugFlag)
              perror ("goodService: can't close old socket");
        }
     else
        tryAgain = 0;
     }
   }

 

Este post ha tratado de alcanzar el límite de clonación debido a un error de codificación, pero qué pasa si no hay ningún error, qué pasa si el entorno de la aplicación está realmente usando todos esos dispositivos de clonación. Bueno, entonces, asumiendo que no has alcanzado el límite del sistema de 16.000 puedes aumentar el límite. Necesitas actualizar el campo clone_limit del dispositivo stcp en el archivo devices.tin y recrear la tabla devices.table. Si está en una versión 17.1 o posterior, puede usar el comando update_device_info para aumentar el límite para el arranque actual y confiar en que el archivo devices.table actualizado se encargará del próximo arranque. En las versiones anteriores a la 17.1 su única opción real es reiniciar. Debe establecer el límite en un valor que corresponda a sus necesidades actuales más el crecimiento esperado; no debe simplemente aumentar el límite a 16.000. Incluso si no tiene un error de aplicación que esté consumiendo dispositivos de clonación ahora, no hay garantía de que no vaya a tener uno en el futuro. Una aplicación que esté consumiendo todos los dispositivos clónicos disponibles también consumirá una gran cantidad de memoria de flujos y el agotamiento de la memoria de flujos afectará negativamente a las conexiones TCP existentes.