Una connessione socket TCP ha un "keep alive"?


85

Ho sentito parlare di HTTP keep-alive, ma per ora voglio aprire una connessione socket con un server remoto.
Ora questa connessione socket rimarrà aperta per sempre o esiste un limite di timeout ad essa associato simile al keep-alive HTTP?


1
Solo per assicurarsi che "http keepalive" non sia tipicamente correlato a socket keepalive, parla della funzionalità HTTP / 1.1 di mantenere aperte le connessioni per ulteriori richieste. È correlato solo a TCP keepalive poiché ha bisogno di rilevare connessioni TCP interrotte (o normalmente mantiene i socket aperti solo per un tempo limitato).
Eckes

Risposte:


70

I socket TCP rimangono aperti finché non vengono chiusi.

Detto questo, è molto difficile rilevare una connessione interrotta (interrotta, come in un router morto, ecc. Invece che chiusa) senza effettivamente inviare dati, quindi la maggior parte delle applicazioni fa una sorta di reazione ping / pong ogni tanto solo per essere sicuri la connessione è ancora effettivamente viva.


4
È una buona idea. Non è necessario , ma se non lo fai, potresti non rilevare un collegamento interrotto finché qualcuno non vuole effettivamente fare qualcosa. Che può o non può essere una buona cosa (o può o non può essere importante), a seconda di ciò che stai effettivamente cercando di ottenere.
Matthew Scharley,

1
@Pacerier: dipende dal protocollo, poiché è totalmente dipendente dal protocollo, ma per i protocolli basati su testo che richiedono un comando letterale "PING" e "PONG" sono piuttosto tipici.
Matthew Scharley

4
@MatthewScharley: Questo "ping pong" è già implementato per noi, nelle implementazioni TCP standard, ed è chiamato "keep-alive" (vedi l'altra risposta popolare a questa domanda). C'è qualche motivo per implementarlo a livello di app?
Tim Cooper

7
@TimCooper: non è davvero. Come ho evidenziato nei commenti su altre risposte, l'implementazione TCP non è utile per la maggior parte dei requisiti a livello di applicazione . Non è possibile inviarne uno su richiesta e per la maggior parte dei sistemi operativi il timeout keepalive TCP è configurabile solo a livello di sistema e impostato troppo alto per essere generalmente utile per le applicazioni.
Matthew Scharley

14
@Tim La ragione per un keep-alive a livello di applicazione è che lo standard TCP consiglia di impostare il timer keep-alive a più di due ore. Non ho mai visto una connessione TCP senza traffico che sopravvive questa volta. Quindi la roba di mantenimento del TCP è inutile per impostazione predefinita.
Robert

99

Ora questa connessione socket rimarrà aperta per sempre o esiste un limite di timeout ad essa associato simile a HTTP keep-alive?

La risposta breve è no , non rimarrà aperto per sempre, probabilmente scadrà dopo poche ore. Quindi sì, c'è un timeout ed è applicata tramite TCP keep-alive .

Se desideri configurare il timeout Keep-Alive sulla tua macchina, consulta la sezione "Modifica dei timeout TCP" di seguito. Altrimenti leggi il resto della risposta per scoprire come funziona TCP Keep-Alive.

introduzione

Le connessioni TCP sono costituite da due socket, uno su ciascuna estremità della connessione. Quando una parte vuole terminare la connessione, invia unRST pacchetto che l'altra parte riconosce ed entrambe chiudono i loro socket.

Fino a quando ciò non accadrà, entrambe le parti manterranno il loro socket aperto a tempo indeterminato. Ciò lascia aperta la possibilità che un lato possa chiudere il proprio zoccolo, intenzionalmente o per qualche errore, senza informare l'altra estremità tramite RST. Per rilevare questo scenario e chiudere le connessioni obsolete, viene utilizzato il processo TCP Keep Alive.

Processo Keep-Alive

Sono disponibili tre proprietà configurabili che determinano il funzionamento di Keep-Alives. Su Linux sono 1 :

  • tcp_keepalive_time
    • predefinito 7200 secondi
  • tcp_keepalive_probes
    • predefinito 9
  • tcp_keepalive_intvl
    • predefinito 75 secondi

Il processo funziona in questo modo:

  1. Il client apre la connessione TCP
  2. Se la connessione è silenziosa per tcp_keepalive_timesecondi, invia un singolo ACKpacchetto vuoto .1
  3. Il server ha risposto con una sua corrispondenza ACK?
    • No
      1. Attendi tcp_keepalive_intvlqualche secondo, quindi invia un altroACK
      2. Ripetere fino a quando il numero di ACKsonde che sono state inviate è uguale tcp_keepalive_probes.
      3. Se non è stata ricevuta alcuna risposta a questo punto, inviare un RSTe terminare la connessione.
    • : torna al passaggio 2

Questo processo è abilitato per impostazione predefinita sulla maggior parte dei sistemi operativi, quindi le connessioni TCP inattive vengono regolarmente eliminate una volta che l'altra estremità non risponde per 2 ore e 11 minuti (7200 secondi + 75 * 9 secondi).

Trabocchetti

Impostazione predefinita di 2 ore

Poiché il processo non si avvia fino a quando una connessione non è rimasta inattiva per due ore per impostazione predefinita, le connessioni TCP obsolete possono persistere per molto tempo prima di essere eliminate. Ciò può essere particolarmente dannoso per connessioni costose come le connessioni al database.

Keep-Alive è opzionale

Secondo RFC 1122 4.2.3.6 , la risposta e / o l'inoltro di pacchetti TCP Keep-Alive è facoltativa :

Gli implementatori POSSONO includere "keep-alive" nelle loro implementazioni TCP, sebbene questa pratica non sia universalmente accettata. Se i keep-alive sono inclusi, l'applicazione DEVE essere in grado di attivarli o disattivarli per ogni connessione TCP e DEVONO essere disattivati ​​per impostazione predefinita.

...

È estremamente importante ricordare che i segmenti ACK che non contengono dati non vengono trasmessi in modo affidabile da TCP.

Il ragionamento è che i pacchetti Keep-Alive non contengono dati e non sono strettamente necessari e rischiano di intasare i tubi degli interweb se abusati.

In pratica , tuttavia , la mia esperienza è stata che questa preoccupazione è diminuita nel tempo man mano che la larghezza di banda è diventata più economica; e quindi i pacchetti Keep-Alive di solito non vengono eliminati. La documentazione di Amazon EC2, ad esempio, fornisce un'approvazione indiretta di Keep-Alive, quindi se stai ospitando con AWS è probabile che tu possa fare affidamento su Keep-Alive, ma il tuo chilometraggio può variare.

Modifica dei timeout TCP

Per socket

Sfortunatamente, poiché le connessioni TCP sono gestite a livello di sistema operativo, Java non supporta la configurazione dei timeout a livello di socket come in java.net.Socket. Ho trovato alcuni tentativi 3 di utilizzare Java Native Interface (JNI) per creare socket Java che chiamano codice nativo per configurare queste opzioni, ma nessuno sembra avere un'adozione o un supporto da parte della comunità diffusa.

Invece, potresti essere costretto ad applicare la tua configurazione al sistema operativo nel suo complesso. Tieni presente che questa configurazione influenzerà tutte le connessioni TCP in esecuzione sull'intero sistema.

Linux

Le impostazioni Keep-Alive TCP attualmente configurate sono disponibili in

  • /proc/sys/net/ipv4/tcp_keepalive_time
  • /proc/sys/net/ipv4/tcp_keepalive_probes
  • /proc/sys/net/ipv4/tcp_keepalive_intvl

Puoi aggiornare uno di questi in questo modo:

# Send first Keep-Alive packet when a TCP socket has been idle for 3 minutes
$ echo 180 > /proc/sys/net/ipv4/tcp_keepalive_time
# Send three Keep-Alive probes...
$ echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes
# ... spaced 10 seconds apart.
$ echo 10 > /proc/sys/net/ipv4/tcp_keepalive_intvl

Tali modifiche non persisteranno dopo un riavvio. Per apportare modifiche persistenti, utilizza sysctl:

sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10

Mac OS X

Le impostazioni attualmente configurate possono essere visualizzate con sysctl:

$ sysctl net.inet.tcp | grep -E "keepidle|keepintvl|keepcnt"
net.inet.tcp.keepidle: 7200000
net.inet.tcp.keepintvl: 75000
net.inet.tcp.keepcnt: 8

Da notare, Mac OS X definisce keepidlee keepintvlin unità di millisecondi rispetto a Linux che utilizza i secondi.

È possibile impostare le proprietà con sysctlcui persisteranno queste impostazioni durante i riavvii:

sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000

In alternativa, puoi aggiungerli a /etc/sysctl.conf(creando il file se non esiste).

$ cat /etc/sysctl.conf
net.inet.tcp.keepidle=180000
net.inet.tcp.keepintvl=10000
net.inet.tcp.keepcnt=3

finestre

Non ho una macchina Windows da confermare, ma dovresti trovare le rispettive impostazioni TCP Keep-Alive nel registro in

\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters

Note a piè di pagina

1. Vedere man tcpper ulteriori informazioni.

2. Questo pacchetto viene spesso definito un pacchetto "Keep-Alive", ma all'interno della specifica TCP è solo un ACKpacchetto normale . Applicazioni come Wireshark sono in grado di etichettarlo come un pacchetto "Keep-Alive" mediante meta-analisi della sequenza e dei numeri di riconoscimento che contiene in riferimento alle precedenti comunicazioni sul socket.

3. Alcuni esempi che ho trovato da una ricerca di base su Google sono lucwilliams / JavaLinuxNet e flonatel / libdontdie .


Molto utile, grazie! Un'aggiunta: per Windows è necessario un riavvio per rendere effettivi i nuovi valori di KeepAliveTime.
geld0r

Su AIX, le attuali impostazioni TCP Keep-Alive possono essere interrogate utilizzando il $ no -a | grep tcp_keepcomando.
Jarek Przygódzki

56

Stai cercando l'opzione socket SO_KEEPALIVE.

L' API Java Socket espone "keep-alive" alle applicazioni tramite i metodi setKeepAlivee getKeepAlive.

EDIT: SO_KEEPALIVE è implementato negli stack del protocollo di rete del sistema operativo senza inviare dati "reali". L'intervallo keep-alive dipende dal sistema operativo e può essere regolato tramite un parametro del kernel.

Poiché non vengono inviati dati, SO_KEEPALIVE può solo testare la vivacità della connessione di rete, non la vivacità del servizio a cui è connesso il socket. Per testare quest'ultimo, è necessario implementare qualcosa che implichi l'invio di messaggi al server e l'ottenimento di una risposta.


4
Se ho un setKeepAlive (true); quale sarebbe l'intervallo? ... inoltre Java continuerà a inviare messaggi keep-alive all'intervallo predefinito o dovrò farlo in modo programmatico?
Kevin Boyd,

3
unixguide.net/network/socketfaq/4.7.shtml Ha una descrizione di SO_KEEPALIVE. Non è tanto quello che voleva l'OP, anche se è un'opzione basata sul protocollo di quello che ho suggerito ... tuttavia, una volta ogni due ore non farà molto per le applicazioni.
Matthew Scharley,

4
@MatthewScharley Riguardo a "non deve essere impostato per impostazione predefinita a non meno di due ore" ... significa che è consentito essere inferiore a due ore, giusto?
Pacerier

1
@MatthewScharley - "Hai ragione, ma sarebbe specifico per l'implementazione ..." . Un intervallo keep-alive che non potrebbe essere inferiore a due ore sarebbe così inutile che è difficile concepire che qualcuno lo attui.
Stephen C

2
@Daniel - l'alternativa (in Java) sarebbe quella di mantenere in vita il manuale , come menzionato sopra e in altre risposte. Non carino, ma forse è meglio di una modifica a livello di sistema operativo dell'impostazione predefinita che potrebbe interrompere i servizi di sistema o altre applicazioni.
Stephen C

34

Keepalive TCP e keepalive HTTP sono concetti molto diversi. In TCP, il keepalive è il pacchetto amministrativo inviato per rilevare la connessione obsoleta. In HTTP, keepalive indica lo stato di connessione persistente.

Questo è dalla specifica TCP,

I pacchetti Keep-Alive DEVONO essere inviati solo quando non sono stati ricevuti dati o pacchetti di riconoscimento per la connessione entro un intervallo. Questo intervallo DEVE essere configurabile e DEVE essere predefinito su non meno di due ore.

Come puoi vedere, l'intervallo di keepalive TCP predefinito è troppo lungo per la maggior parte delle applicazioni. Potrebbe essere necessario aggiungere keepalive nel protocollo dell'applicazione.


2
È possibile modificare l'intervallo keepalive TCP per adattarlo alla propria applicazione. Ad esempio msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx
Dan Berindei

@ZZCoder Puoi spiegare cosa significa quando dici "In HTTP, keepalive significa lo stato di connessione persistente"?
Pacerier

1
@Pacerier: in HTTP/1.0ogni richiesta / risposta era necessaria la riconnessione al server. Perché HTTP/1.1hanno introdotto Keep-Aliveun'intestazione che potrebbe essere utilizzata per attivare il server in modo che non interrompa la connessione dopo aver elaborato la risposta per facilitare la richiesta di più file e consentire il "pipelining"; inviare più richieste e poi attendere il ritorno di tutti i dati.
Matthew Scharley,

Fondamentalmente significa che molte richieste HTTP riutilizzeranno / dovrebbero riutilizzare la stessa connessione TCP (queste connessioni potrebbero anche avere keep-alive ma questo non si misura con HTTP, quindi è essenzialmente un concetto diverso).
Igor Čordaš

24

Se sei dietro un NAT mascherato (come la maggior parte degli utenti domestici in questi giorni), c'è un pool limitato di porte esterne e queste devono essere condivise tra le connessioni TCP. Pertanto i NAT mascherati tendono a presumere che una connessione sia stata interrotta se non sono stati inviati dati per un certo periodo di tempo.

Questo e altri problemi simili (ovunque tra i due endpoint) possono significare che la connessione non "funzionerà" più se si tenta di inviare dati dopo un ragionevole periodo di inattività. Tuttavia, potresti non scoprirlo finché non provi a inviare i dati.

L'uso di keepalive riduce la possibilità che la connessione venga interrotta da qualche parte lungo la linea e ti consente anche di scoprire prima una connessione interrotta.


Ah! aggiungi un buon punto qui, cioè devi considerare anche le cose intermedie che potrebbero ostacolare il funzionamento di una connessione come i router NAT ecc ...
Kevin Boyd,

4
Questo è un buon punto e un buon promemoria che c'è molto di più da tenere a mente oltre a ciò che stiamo implementando direttamente noi stessi. Inoltre, Lemmings !!
Matthew Scharley,

Si noti che la condivisione di file p2p mastica molte porte e produce molte connessioni zombie, rendendo più probabile che il NAT debba eliminare le connessioni inattive.
Artelius

4
Non necessariamente, una connessione TCP è identificata da 4 elementi: src ip, src port, dest ip, dest port. Quindi puoi riutilizzare la stessa porta esterna (sorgente) purché l'ip di destinazione sia diverso.
Dan Berindei

1
Oh sì, hai ragione. Penso che la vera ragione sia che i NAT hanno una tabella di dimensioni fisse di connessioni aperte, a causa dei vincoli di memoria e del tempo di ricerca.
Artelius

4

Ecco un po 'di letteratura supplementare su keepalive che lo spiega in modo molto più dettagliato.

http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO

Poiché Java non consente di controllare i tempi effettivi di keepalive, è possibile utilizzare gli esempi per modificarli se si utilizza un kernel Linux (o un sistema operativo basato su proc).


1

In JAVA Socket: le connessioni TCP sono gestite a livello di sistema operativo, java.net.Socket non fornisce alcuna funzione incorporata per impostare i timeout per il pacchetto keepalive a livello di socket. Ma possiamo abilitare l'opzione keepalive per il socket java ma ci vogliono 2 ore e 11 minuti (7200 sec) per impostazione predefinita per l'elaborazione dopo una connessione TCP obsoleta. Questa connessione causa sarà disponibile per molto tempo prima dell'eliminazione. Quindi abbiamo trovato una soluzione per utilizzare Java Native Interface (JNI) che chiama il codice nativo (c ++) per configurare queste opzioni.

**** Sistema operativo Windows ****

Nel sistema operativo Windows keepalive_time e keepalive_intvl possono essere configurabili ma tcp_keepalive_probes non può essere modificato. Per impostazione predefinita, quando un socket TCP viene inizializzato, imposta il timeout keep-alive a 2 ore e l'intervallo keep-alive a 1 secondo. Il valore predefinito a livello di sistema del timeout keep-alive è controllabile tramite l'impostazione del registro KeepAliveTime che assume un valore in millisecondi.

In Windows Vista e versioni successive, il numero di sonde keep-alive (ritrasmissioni di dati) è impostato su 10 e non può essere modificato.

In Windows Server 2003, Windows XP e Windows 2000, l'impostazione predefinita per il numero di probe keep-alive è 5. Il numero di probe keep-alive è controllabile. Per Windows, la libreria IOCTL di Winsock viene utilizzata per configurare i parametri tcp-keepalive.

int WSAIoctl (SocketFD, // descrittore che identifica un socket SIO_KEEPALIVE_VALS, // dwIoControlCode (LPVOID) lpvInBuffer, // puntatore a tcp_keepalive struct (DWORD) cbInBuffer, // length of input buffer NULL, // output buffer 0, // size of buffer di output (LPDWORD) lpcbBytesReturned, // numero di byte restituiti NULL, // struttura OVERLAPPED NULL // routine di completamento);

Sistema operativo Linux

Linux ha il supporto integrato per keepalive che deve abilitare il networking TCP / IP per poterlo utilizzare. I programmi devono richiedere il controllo keepalive per i loro socket utilizzando l'interfaccia setsockopt.

int setsockopt (int socket, int level, int optname, const void * optval, socklen_t optlen)

Ogni socket client verrà creato utilizzando java.net.Socket. L'ID descrittore di file per ogni socket verrà recuperato utilizzando la riflessione java.


0

Per Windows secondo Microsoft docs

  • KeepAliveTime (REG_DWORD, millisecondi, per impostazione predefinita non è impostato, il che significa 7.200.000.000 = 2 ore) - analogo a tcp_keepalive_time
  • KeepAliveInterval (REG_DWORD, millisecondi, per impostazione predefinita non è impostato, il che significa 1.000 = 1 secondo) - analogo a tcp_keepalive_intvl
  • Poiché in Windows Vista non esiste un analogo a tcp_keepalive_probes, il valore è fisso su 10 e non può essere modificato
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.