In questo post vorrei discutere di un errore di codifica comune che può portare ad un modulo che esaurisce o almeno esaurisce seriamente il numero disponibile di cloni di dispositivi stcp da utilizzare per la creazione di prese TCP.
Ogni chiamata alla funzione socket comporta la creazione di un nuovo clone del dispositivo stcp da parte di STCP. Il numero massimo di cloni che possono essere creati è controllato dal campo clone_limit nella voce devices.tin.
/ =nome stcp.m17
=nome_modulo m17
=flussi di tipo_dispositivo
=accesso_elenco_nome_lista stcp_accesso
=streams_driver stcp
=clone_limit 5120
=commento Fornisce API TCP
|
Si può vedere quanti cloni sono attualmente in uso scaricando la struttura del dispositivo in analyz_system e guardando il valore di clone_count. Se clone_count è uguale a clone_limit, le chiamate alla funzione socket restituiranno un e$clone_limit_exceeded: Errore "Il limite del clone per il dispositivo è stato superato".
come: clone match; dump_dvt - nome stcp.m17
clone_limit: 5120
clone_count: 42
clonato_da: -27271
limite_clone_remoto: 0
|
In generale, la chiamata della presa che crea il dispositivo clone è seguita da un collegatevi a chiamare o legare e ascoltare chiamate. A quel punto si può vedere una voce corrispondente quando si esegue il "comando netstat".
netstat -numerico - tutte_prese_tutte_tutte_le_prese Connessioni attive (compresi i server) Proto Recv-Q Send-Q Indirizzo locale Indirizzo estero (stato) tcp 0 0 172.16.124.217:23 192.168.109.22:50038 ISTITUITO tcp 0 0 172.16.124.217:22 172.16.124.24:54987 ISTITUITO 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 ISTITUITO tcp 0 0 172.16.124.217:22 172.16.124.50:17421 ISTITUITO tcp 0 0 172.16.124.217:22 172.16.124.50:17658 ISTITUITO tcp 0 0 0 *:23 *:* ASCOLTA tcp 0 0 0 *:6666 *:* ASCOLTO tcp 0 0 0 *:21 *:* ASCOLTA tcp 0 0 0 *:3000 *:* ASCOLTA tcp 0 0 0 *:7 *:* ASCOLTA tcp 0 0 0 *:9 *:*:* ASCOLTA tcp 0 0 0 *:13 *:* ASCOLTA tcp 0 0 0 *:19 *:* ASCOLTA tcp 0 0 0 *:37 *:* ASCOLTA tcp 0 0 0 *:901 *:*:* ASCOLTA tcp 0 0 0 *:1414 *:* ASCOLTA tcp 0 0 0 *:81 *:* ASCOLTA 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 STABILITATO tcp 0 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 ISTITUITO tcp 0 0 0 *:3001 *:* ASCOLTA tcp 0 0 0 *:3002 *:* ASCOLTA tcp 0 0 0 *:3003 *:* ASCOLTA tcp 0 0 0 *:4000 *:* ASCOLTA tcp 0 0 172.16.124.217:4000 172.16.124.78:1024 ISTITUITO tcp 0 0 172.16.124.217:4000 172.16.124.227:1025 ISTITUITO tcp 0 0 0 *:4001 *:* Ascolta tcp 0 0 0 *:4002 *:* ASCOLTA tcp 0 0 0 *:4003 *:* ASCOLTA tcp 0 0 0 *:4004 *:* ASCOLTA tcp 0 0 0 *:22 *:* ASCOLTA tcp 0 0 0 *:4005 *:* ASCOLTA tcp 0 0 0 *:4006 *:* ASCOLTA tcp 0 0 172.16.124.217:4006 172.16.124.203:49231 ISTITUITO tcp 0 0 0 *:4007 *:* ASCOLTA tcp 0 0 0 *:4008 *:* ASCOLTA tcp 0 0 0 *:4009 *:* ASCOLTA tcp 0 0 172.16.124.217:4008 172.16.124.203:49262 ISTITUITO tcp 0 0 0 *:4010 *:* Ascolta tcp 0 0 0 *:4011 *:* ASCOLTO tcp 0 0 0 *:4012 *:* ASCOLTO tcp 0 0 0 *:4013 *:* ASCOLTO tcp 0 0 0 *:4014 *:* ASCOLTO tcp 0 0 0 *:4015 *:* ASCOLTO tcp 0 0 0 *:80 *:*:* ASCOLTA tcp 0 0 0 *:9182 *:* ASCOLTO tcp 0 0 0 *:445 *:* ASCOLTO tcp 0 0 0 *:139 *:* ASCOLTA tcp 0 0 10.20.1.1:53495 10.20.1.9:48879 ISTITUITO tcp 0 0 10.20.1.1:61703 10.20.1.3:48879 ISTITUITO tcp 0 0 10.20.1.1:61707 10.20.1.3:48879 ISTITUITO tcp 0 0 10.20.1.1:61705 10.20.1.9:48879 ISTITUITO tcp 0 0 10.20.1.1:61709 10.20.1.9:48879 ISTITUITO tcp 0 0 10.20.1.1:61710 10.20.1.9:48879 ISTITUITO tcp 0 0 172.16.124.217:61789 172.16.124.203:4000 ISTITUITO tcp 0 400 172.16.124.217:22 172.16.124.50:17674 ISTITUITO |
Se si conta il numero di righe si vedranno più di 42, questo perché non tutte le voci mostrate da netstat utilizzano un clone di dispositivo stcp. Per esempio, le connessioni OSL e le connessioni X25_cpc utilizzate con il NIO. Date un'occhiata a socket_count.cm per maggiori dettagli.
Se una chiamata alla presa viene effettuata senza un collegamento o un bind o il bind fallisce è possibile creare il problema opposto, il valore di clone_count è maggiore del numero di voci mostrato da netstat.
come: clone match; dump_dvt - nome stcp.m17
clone_limit: 5120
clone_count: 4131
clonato_da: -23179
limite_clone_remoto: 0
come:
|
Non includo di nuovo l'output netstat, ma credetemi, non è cambiato rispetto all'esempio precedente.
Questa situazione, un ulteriore (4131 - 42) e apparentemente non contabilizzata, cloni di dispositivi STCP è stata creata dal seguente frammento di codice. Il codice chiama la funzione socket seguita dalla funzione bind. Se il bind fallisce, il codice si chiude in loop. Molte applicazioni aggiungerebbero un timer per attendere 1, 60, o 300 secondi e riprovare, che ritarda solo l'inevitabile, supponendo ovviamente che la condizione che causa l'errore non vada via.
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; } } |
L'errore più comune è che un altro processo è già legato alla porta richiesta. Indipendentemente dal motivo dell'errore, la soluzione è quella di chiudere il socket dopo aver segnalato l'errore di binding.
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;
}
}
|
Questo post parlava di raggiungere il clone_limit a causa di un errore di codifica, ma cosa succede se non c'è nessun errore, cosa succede se l'ambiente applicativo sta realmente usando tutti quei dispositivi di clonazione. Bene allora, supponendo di non aver raggiunto il limite di sistema di 16.000 è possibile aumentare il limite. È necessario aggiornare il campo clone_limit del dispositivo stcp nel file devices.tin e ricreare il device.table. Se siete su una release 17.1 o successiva potete usare il comando update_device_info per aumentare il limite per l'avvio corrente e fare affidamento sul device.table aggiornato devices.table per occuparvi del prossimo avvio. Nelle release precedenti alla 17.1 l'unica opzione reale è il riavvio. Si dovrebbe impostare il limite ad un valore che corrisponda alle proprie esigenze attuali più la crescita prevista; non si dovrebbe semplicemente aumentare il limite a 16.000. Anche se non si dispone di un bug dell'applicazione che sta consumando dispositivi di clonazione ora non c'è garanzia che non ne avrete uno in futuro. Un'applicazione che sta consumando tutti i dispositivi di clonazione disponibili consumerà anche una grande quantità di memoria di flussi e l'esaurimento della memoria dei flussi influenzerà negativamente le connessioni TCP esistenti.