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?
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?
Risposte:
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.
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.
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.
Sono disponibili tre proprietà configurabili che determinano il funzionamento di Keep-Alives. Su Linux sono 1 :
tcp_keepalive_time
tcp_keepalive_probes
tcp_keepalive_intvl
Il processo funziona in questo modo:
tcp_keepalive_time
secondi, invia un singolo ACK
pacchetto vuoto .1ACK
?
tcp_keepalive_intvl
qualche secondo, quindi invia un altroACK
ACK
sonde che sono state inviate è uguale tcp_keepalive_probes
.RST
e terminare la connessione.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).
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.
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.
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.
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
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 keepidle
e keepintvl
in unità di millisecondi rispetto a Linux che utilizza i secondi.
È possibile impostare le proprietà con sysctl
cui 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
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 tcp
per ulteriori informazioni.
2. Questo pacchetto viene spesso definito un pacchetto "Keep-Alive", ma all'interno della specifica TCP è solo un ACK
pacchetto 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 .
$ no -a | grep tcp_keep
comando.
Stai cercando l'opzione socket SO_KEEPALIVE.
L' API Java Socket espone "keep-alive" alle applicazioni tramite i metodi setKeepAlive
e 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.
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.
HTTP/1.0
ogni richiesta / risposta era necessaria la riconnessione al server. Perché HTTP/1.1
hanno introdotto Keep-Alive
un'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.
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.
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).
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.
Per Windows secondo Microsoft docs