Ich habe von HTTP Keep-Alive gehört, möchte aber vorerst eine Socket-Verbindung mit einem Remote-Server herstellen.
Bleibt diese Socket-Verbindung nun für immer offen oder ist damit ein Timeout-Limit verbunden, das dem HTTP-Keep-Alive ähnelt?
Ich habe von HTTP Keep-Alive gehört, möchte aber vorerst eine Socket-Verbindung mit einem Remote-Server herstellen.
Bleibt diese Socket-Verbindung nun für immer offen oder ist damit ein Timeout-Limit verbunden, das dem HTTP-Keep-Alive ähnelt?
Antworten:
TCP-Sockets bleiben offen, bis sie geschlossen werden.
Das heißt, es ist sehr schwierig, eine unterbrochene Verbindung zu erkennen (unterbrochen, wie bei einem Router gestorben usw., im Gegensatz zu geschlossen), ohne tatsächlich Daten zu senden. Daher führen die meisten Anwendungen von Zeit zu Zeit eine Art Ping / Pong-Reaktion durch, um sicherzugehen Die Verbindung ist noch aktiv.
Bleibt diese Socket-Verbindung nun für immer offen oder ist damit ein Timeout-Limit verbunden, das dem HTTP-Keep-Alive ähnelt?
Die kurze Antwort lautet: Nein, es wird nicht für immer geöffnet bleiben, es wird wahrscheinlich nach ein paar Stunden eine Zeitüberschreitung auftreten. Daher gibt es ja eine Zeitüberschreitung, die über TCP Keep-Alive erzwungen wird .
Wenn Sie das Keep-Alive-Zeitlimit auf Ihrem Computer konfigurieren möchten, lesen Sie den folgenden Abschnitt "Ändern der TCP-Zeitlimits". Lesen Sie andernfalls den Rest der Antwort durch, um zu erfahren, wie TCP Keep-Alive funktioniert.
TCP-Verbindungen bestehen aus zwei Sockets, einer an jedem Ende der Verbindung. Wenn eine Seite die Verbindung beenden möchte, sendet sie ein RST
Paket, das die andere Seite bestätigt, und beide schließen ihre Sockets.
Bis dies jedoch passiert, halten beide Seiten ihre Steckdose auf unbestimmte Zeit offen. Dies lässt die Möglichkeit offen, dass eine Seite ihre Buchse absichtlich oder aufgrund eines Fehlers schließt, ohne das andere Ende über zu informieren RST
. Um dieses Szenario zu erkennen und veraltete Verbindungen zu schließen, wird der TCP Keep Alive-Prozess verwendet.
Es gibt drei konfigurierbare Eigenschaften, die bestimmen, wie Keep-Alives funktionieren. Unter Linux sind sie 1 :
tcp_keepalive_time
tcp_keepalive_probes
tcp_keepalive_intvl
Der Prozess funktioniert folgendermaßen:
tcp_keepalive_time
Sekunden still ist , senden Sie ein einzelnes leeres ACK
Paket. 1ACK
geantwortet?
tcp_keepalive_intvl
Sekunden und senden Sie dann eine weitereACK
ACK
gesendeten Sonden gleich ist tcp_keepalive_probes
.RST
und beenden Sie die Verbindung.Dieser Prozess ist auf den meisten Betriebssystemen standardmäßig aktiviert. Daher werden tote TCP-Verbindungen regelmäßig gelöscht, sobald das andere Ende 2 Stunden 11 Minuten (7200 Sekunden + 75 * 9 Sekunden) nicht reagiert hat.
Da der Prozess erst startet, wenn eine Verbindung standardmäßig zwei Stunden lang inaktiv war, können veraltete TCP-Verbindungen sehr lange bestehen bleiben, bevor sie gelöscht werden. Dies kann besonders für teure Verbindungen wie Datenbankverbindungen schädlich sein.
Gemäß RFC 1122 4.2.3.6 ist das Beantworten und / oder Weiterleiten von TCP Keep-Alive-Paketen optional :
Implementierer KÖNNEN "Keep-Alives" in ihre TCP-Implementierungen aufnehmen, obwohl diese Praxis nicht allgemein akzeptiert wird. Wenn Keep-Alives enthalten sind, MUSS die Anwendung sie für jede TCP-Verbindung ein- oder ausschalten können, und sie MÜSSEN standardmäßig deaktiviert sein.
...
Es ist äußerst wichtig zu bedenken, dass ACK-Segmente, die keine Daten enthalten, nicht zuverlässig von TCP übertragen werden.
Der Grund dafür ist, dass Keep-Alive-Pakete keine Daten enthalten und nicht unbedingt erforderlich sind und bei Überbeanspruchung die Röhren der Interwebs verstopfen können.
In der Praxis habe ich jedoch die Erfahrung gemacht, dass diese Bedenken im Laufe der Zeit nachgelassen haben, da die Bandbreite billiger geworden ist. und daher werden Keep-Alive-Pakete normalerweise nicht verworfen. In der Amazon EC2-Dokumentation wird beispielsweise Keep-Alive indirekt empfohlen. Wenn Sie also mit AWS hosten, können Sie sich sicher auf Keep-Alive verlassen, aber Ihr Kilometerstand kann variieren.
Da TCP-Verbindungen auf Betriebssystemebene verwaltet werden, unterstützt Java leider nicht die Konfiguration von Zeitüberschreitungen auf Socket-Ebene wie in java.net.Socket
. Ich habe einige Versuche 3 gefunden , Java Native Interface (JNI) zu verwenden, um Java-Sockets zu erstellen, die nativen Code zum Konfigurieren dieser Optionen aufrufen, aber keiner scheint eine breite Akzeptanz oder Unterstützung durch die Community zu haben.
Stattdessen müssen Sie möglicherweise Ihre Konfiguration auf das gesamte Betriebssystem anwenden. Beachten Sie, dass diese Konfiguration alle TCP-Verbindungen betrifft, die auf dem gesamten System ausgeführt werden.
Die aktuell konfigurierten TCP Keep-Alive-Einstellungen finden Sie unter
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_probes
/proc/sys/net/ipv4/tcp_keepalive_intvl
Sie können Folgendes aktualisieren:
# 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
Solche Änderungen bleiben bei einem Neustart nicht bestehen. Verwenden Sie Folgendes, um dauerhafte Änderungen vorzunehmen sysctl
:
sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10
Die aktuell konfigurierten Einstellungen können angezeigt werden mit 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
Bemerkenswerterweise definiert Mac OS X keepidle
und keepintvl
in Millisekunden im Gegensatz zu Linux, das Sekunden verwendet.
Es können die Eigenschaften festgelegt werden, mit sysctl
denen diese Einstellungen bei Neustarts beibehalten werden:
sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000
Alternativ können Sie sie hinzufügen /etc/sysctl.conf
(Erstellen der Datei, falls nicht vorhanden).
$ cat /etc/sysctl.conf
net.inet.tcp.keepidle=180000
net.inet.tcp.keepintvl=10000
net.inet.tcp.keepcnt=3
Ich habe keinen Windows-Computer zur Bestätigung, aber Sie sollten die entsprechenden TCP Keep-Alive-Einstellungen in der Registrierung unter finden
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
Fußnoten
1. man tcp
Weitere Informationen finden Sie unter.
2. Dieses Paket wird häufig als "Keep-Alive" -Paket bezeichnet, innerhalb der TCP-Spezifikation handelt es sich jedoch nur um ein reguläres ACK
Paket. Anwendungen wie Wireshark können es durch Metaanalyse der Sequenz- und Bestätigungsnummern, die es in Bezug auf die vorhergehenden Mitteilungen auf dem Socket enthält, als "Keep-Alive" -Paket kennzeichnen.
3. Einige Beispiele, die ich bei einer einfachen Google-Suche gefunden habe, sind lucwilliams / JavaLinuxNet und flonatel / libdontdie .
$ no -a | grep tcp_keep
Befehl abgefragt werden .
Sie suchen nach der Socket-Option SO_KEEPALIVE.
Die Java Socket-API macht Anwendungen über die Methoden setKeepAlive
und für Anwendungen "Keep-Alive" getKeepAlive
.
BEARBEITEN: SO_KEEPALIVE wird in den Netzwerkprotokollstapeln des Betriebssystems implementiert, ohne dass "echte" Daten gesendet werden. Das Keep-Alive-Intervall ist betriebssystemabhängig und kann über einen Kernel-Parameter eingestellt werden.
Da keine Daten gesendet werden, kann SO_KEEPALIVE nur die Lebensdauer der Netzwerkverbindung testen, nicht die Lebensdauer des Dienstes, mit dem der Socket verbunden ist. Um letzteres zu testen, müssen Sie etwas implementieren, bei dem Nachrichten an den Server gesendet und eine Antwort erhalten werden.
TCP Keepalive und HTTP Keepalive sind sehr unterschiedliche Konzepte. In TCP ist das Keepalive das Verwaltungspaket, das gesendet wird, um eine veraltete Verbindung zu erkennen. In HTTP bedeutet Keepalive den dauerhaften Verbindungsstatus.
Dies ist aus der TCP-Spezifikation,
Keep-Alive-Pakete MÜSSEN nur gesendet werden, wenn innerhalb eines Intervalls keine Daten oder Bestätigungspakete für die Verbindung empfangen wurden. Dieses Intervall MUSS konfigurierbar sein und standardmäßig mindestens zwei Stunden betragen.
Wie Sie sehen, ist das Standard-TCP-Keepalive-Intervall für die meisten Anwendungen zu lang. Möglicherweise müssen Sie Keepalive in Ihr Anwendungsprotokoll aufnehmen.
HTTP/1.0
jeder Anfrage / Antwort musste erneut eine Verbindung zum Server hergestellt werden. Denn HTTP/1.1
sie führten einen Keep-Alive
Header ein, der verwendet werden konnte, um den Server zu veranlassen, die Verbindung nicht zu beenden, nachdem die Antwort verarbeitet wurde, um das Anfordern weiterer Dateien und das Ermöglichen von "Pipelining" zu erleichtern. Senden mehrerer Anfragen und Warten auf die Rückgabe aller Daten.
Wenn Sie sich hinter einem maskierenden NAT befinden (wie es die meisten Heimanwender heutzutage tun), gibt es einen begrenzten Pool externer Ports, die von den TCP-Verbindungen gemeinsam genutzt werden müssen. Maskierende NATs gehen daher davon aus, dass eine Verbindung beendet wurde, wenn für einen bestimmten Zeitraum keine Daten gesendet wurden.
Dieses und andere derartige Probleme (irgendwo zwischen den beiden Endpunkten) können dazu führen, dass die Verbindung nicht mehr "funktioniert", wenn Sie versuchen, Daten nach einer angemessenen Leerlaufzeit zu senden. Möglicherweise stellen Sie dies jedoch erst fest, wenn Sie versuchen , Daten zu senden.
Keepalives beide verwenden wird die Wahrscheinlichkeit verringert, dass die Verbindung irgendwo auf der ganzen Linie unterbrochen wird, und Sie können auch früher feststellen, dass die Verbindung unterbrochen wurde.
Hier ist eine ergänzende Literatur zu Keepalive, die es viel detaillierter erklärt.
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO
Da Sie mit Java die tatsächlichen Keepalive-Zeiten nicht steuern können, können Sie sie anhand der Beispiele ändern, wenn Sie einen Linux-Kernel (oder ein prozessbasiertes Betriebssystem) verwenden.
In JAVA Socket - TCP-Verbindungen werden auf Betriebssystemebene verwaltet. Java.net.Socket bietet keine integrierte Funktion zum Festlegen von Zeitüberschreitungen für Keepalive-Pakete auf Socket-Ebene. Wir können die Keepalive-Option für Java-Sockets aktivieren, die Verarbeitung nach veralteten TCP-Verbindungen dauert jedoch standardmäßig 2 Stunden 11 Minuten (7200 Sekunden). Diese Ursache Verbindung wird sehr lange vor dem Löschen verfügbar sein. Daher haben wir eine Lösung gefunden, um Java Native Interface (JNI) zu verwenden, die nativen Code (c ++) aufruft, um diese Optionen zu konfigurieren.
**** Windows-Betriebssystem ****
Unter Windows-Betriebssystemen können keepalive_time & keepalive_intvl konfigurierbar sein, tcp_keepalive_probes kann jedoch nicht geändert werden. Standardmäßig wird bei der Initialisierung eines TCP-Sockets das Keep-Alive-Timeout auf 2 Stunden und das Keep-Alive-Intervall auf 1 Sekunde festgelegt. Der systemweite Standardwert des Keep-Alive-Timeouts kann über die Registrierungseinstellung KeepAliveTime gesteuert werden, die einen Wert in Millisekunden annimmt.
Unter Windows Vista und höher ist die Anzahl der Keep-Alive-Tests (erneute Datenübertragung) auf 10 festgelegt und kann nicht geändert werden.
Unter Windows Server 2003, Windows XP und Windows 2000 beträgt die Standardeinstellung für die Anzahl der Keep-Alive-Tests 5. Die Anzahl der Keep-Alive-Tests kann gesteuert werden. Für Windows Die Winsock IOCTLs-Bibliothek wird zum Konfigurieren der tcp-keepalive-Parameter verwendet.
int WSAIoctl (SocketFD, // Deskriptor zur Identifizierung eines Sockets SIO_KEEPALIVE_VALS, // dwIoControlCode (LPVOID) lpvInBuffer, // Zeiger auf tcp_keepalive struct (DWORD) cbInBuffer, // Länge des Eingabepuffers NULL, // Ausgabepuffer 0, // Größe Ausgabepuffer (LPDWORD) lpcbBytesReturned, // Anzahl der zurückgegebenen Bytes NULL, // OVERLAPPED-Struktur NULL // Abschlussroutine);
Linux-Betriebssystem
Linux verfügt über eine integrierte Unterstützung für Keepalive, die TCP / IP-Netzwerke aktivieren muss, um es verwenden zu können. Programme müssen über die setsockopt-Schnittstelle eine Keepalive-Kontrolle für ihre Sockets anfordern.
int setsockopt (int socket, int level, int optname, const void * optval, socklen_t optlen)
Jeder Client-Socket wird mit java.net.Socket erstellt. Die Dateideskriptor-ID für jeden Socket wird mithilfe von Java Reflection abgerufen.
Für Windows gemäß Microsoft-Dokumenten