Passa al contenuto principale

A volte netstat mostra un socket che sembra bloccato. L'applicazione remota è stata chiusa, a volte anche l'applicazione OpenVOS è stata chiusa, ma netstat continua a mostrare il socket. Questo articolo spiega perché ciò accade e cosa è possibile fare al riguardo.

Breve introduzione agli stati TCP

Se cerchi su Google "diagramma di stato TCP", troverai una miriade di immagini, alcune appena leggibili, altre piuttosto chiare. Wikimedia ne ha uno molto bello con codifica a colori (http://commons.wikimedia.org/wiki/File:TCP_state_diagram.png). Il TCP RFC (793) (http://www.rfc-editor.org/rfc/rfc793.txt) presenta un diagramma in ASCII art e, naturalmente, spiega gli stati in dettaglio.

I socket possono bloccarsi quando sono in attesa che l'applicazione locale o l'host remoto eseguano un'operazione. Ciò può verificarsi in tre stati diversi. Nello stato FIN_WAIT_2, il socket è in attesa che l'host remoto chiuda la connessione. Nello stato CLOSE_WAIT, aspetta che l'applicazione locale chiuda il socket e nello stato ESTABLISHED aspetta che l'host remoto apra la sua finestra di invio o che l'applicazione locale invii qualcosa. Se lo stack TCP locale ha inviato dati e sta aspettando che l'host remoto li confermi, non può bloccarsi, ma alla fine andrà in timeout, segnalerà un errore all'applicazione locale e chiuderà il socket.

Stato FIN_WAIT_2

Questo è forse il caso più comune di socket bloccato segnalato al CAC. L'applicazione locale ha chiuso il socket e potrebbe essersi terminata. Il motivo tipico per cui i socket rimangono bloccati in questo stato è che l'applicazione remota è bloccata e non legge il proprio socket.

Impostando il parametro STCP finwait2 su un valore N > 0, i socket verranno chiusi dopo essere rimasti in FIN_WAIT_2 per N secondi. A partire dalle versioni 14.7.2bg, 14.7.tl1, 15.2.1aa, 15.2.tel.af, 15.3.0bd, 15.3.tel.ag, 16.2.1al, 17.0.0ai e 17.1 il valore predefinito è 1200, mentre prima era 0 (quindi, se si desidera che i socket scadano, è necessario impostarlo manualmente). È possibile visualizzare il valore corrente con la richiesta list_stcp_params analyze_system, mentre è possibile modificare il valore con la richiesta set_stcp_param analyze_system. Per la documentazione relativa a queste richieste, consultare il manuale OpenVOS System Analysis (R073), disponibile all'indirizzostratus

Stato CLOSE_WAIT

Questo è il secondo stato più comune in cui un socket può rimanere bloccato. I socket in stato CLOSE_WAIT sono in attesa che l'applicazione locale chiuda il socket. Il motivo tipico per cui un socket rimane in questo stato è che l'applicazione non sta più leggendo il socket. Il modo più semplice per chiudere il socket è terminare l'applicazione locale.

Se non è possibile terminare l'applicazione locale, l'unica cosa che puoi fare è creare un pacchetto con il flag RST (reset) impostato. Per farlo, devi conoscere i numeri di sequenza utilizzati dal socket (disponibili tramite la richiesta dump_onetcb analyze_system) e avere un'utilità su un altro host nella sottorete locale in grado di creare e inviare pacchetti IP personalizzati. Queste utilità sono disponibili per i sistemi Windows e Linux.

Stato STABILITO

Poiché la maggior parte delle volte netstat mostra i socket nello stato ESTABLISHED, come è possibile capire quando il socket è bloccato? Se si riceve una segnalazione che l'host remoto si è bloccato o che la rete tra l'host locale e quello remoto non funziona da più di 10 minuti e l'applicazione locale è in attesa che quella remota le invii qualcosa, si può essere abbastanza sicuri che il socket sia bloccato. In questo caso, il valore della coda di invio (il numero immediatamente a sinistra dell'indirizzo IP locale) riportato da netstat sarà 0. D'altra parte, se il valore della coda di invio è maggiore di 0 e rimane tale, è possibile che l'host remoto stia segnalando una finestra zero.

Nel primo caso, a meno che keep-alive non sia attivato, il socket rimarrà nello stato ESTABLISHED fino alla chiusura dell'applicazione locale. Se keep-alive è attivato, allo scadere del timer keep-alive, STCP invierà una sonda keep-alive. Se la sonda non riceve risposta, verrà ritrasmessa, ma dopo alcuni minuti e diverse ritrasmissioni la connessione verrà chiusa. Per impostazione predefinita, l'interfaccia ha il keep-alive impostato, ma per impostazione predefinita i socket no. Per impostare il keep-alive su un socket, l'applicazione deve utilizzare la chiamata di funzione setsockopt. Per ulteriori dettagli, consultare il manuale OpenVOS STREAMS TCP/IP Programming (R420), disponibile anche all'indirizzostratus. Il tempo di keep-alive predefinito è di 2 ore; ciò significa che la prima sonda keep-alive viene trasmessa 2 ore dopo la ricezione dell'ultimo segmento TCP dall'host remoto, quindi è necessario essere pazienti. Per chi non è così paziente, è possibile regolare il tempo di keep-alive, nonché il tempo tra le sonde e il numero di sonde con la richiesta set_stcp_parameter all'interno di analyze_system. Si sconsiglia di modificare questi parametri senza un'analisi dettagliata.

Se il socket non ha il keep-alive impostato, l'unica opzione semplice è terminare l'applicazione che possiede il socket. Se ciò non è possibile, è possibile chiudere il socket inviandogli un segmento con il flag RST impostato.

Per confermare il secondo caso, controllare il valore di sndws visualizzato dalla richiesta dump_onetcb analyze_system. Un valore 0 indica una finestra chiusa. È anche possibile eseguire packet_monitor per tracciare la connessione e controllare il valore della finestra nell'intestazione TCP nei segmenti provenienti dall'host remoto. Un valore "n.a." indica 0.

Vorrei sottolineare che questa potrebbe essere una condizione recuperabile. A volte le applicazioni subiscono ritardi e lo stack TCP chiude la finestra, ma quando l'applicazione viene recuperata lo stack riapre la finestra. Tuttavia, nella maggior parte dei casi penso che sia lecito supporre che se l'applicazione non si è ripristinata dopo alcuni minuti, non lo farà più. L'eccezione potrebbe essere qualcosa come una stampante che ha esaurito la carta. Un socket in questo stato può rimanere tale anche se l'applicazione VOS che lo ha creato viene terminata.

Questi socket possono essere ripuliti impostando tcp_zerowin_abort_interval$ su un valore N > 0. I socket verranno ripuliti N secondi dopo la ricezione del segmento TCP successivo con una finestra zero. Le sondaggi della finestra vengono inviati ogni 100 secondi per confermare che la finestra di ricezione dell'host remoto sia ancora chiusa, quindi nel peggiore dei casi una risposta verrà ricevuta entro 100 secondi. Il valore predefinito di tcp_zerowin_abort_interval$ è zero e suggerisco di mantenerlo a 0 a meno che non sia necessario pulire un socket. A quel punto suggerisco di impostarlo su un valore piccolo, ad esempio 10 secondi, e una volta pulito il socket reimpostarlo a 0. Penso che questo riduca il rischio di cancellare socket che sono recuperabili.

Per impostare questo valore è necessario utilizzare la richiesta set_longword in analyze_system, quindi ricordate che N sarà in esadecimale. Ad esempio, per impostarlo su 10, la richiesta sarebbe:
set_longword tcp_zerowin_abort_interval$ a