Hat eine TCP-Socket-Verbindung ein "Keep Alive"?


83

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?


1
Um sicherzustellen, dass "http keepalive" normalerweise nicht mit Socket keepalive zusammenhängt, wird die HTTP / 1.1-Funktion zum Offenhalten von Verbindungen für weitere Anforderungen beschrieben. Es bezieht sich nur auf TCP Keepalive, da es unterbrochene TCP-Verbindungen erkennen muss (oder normalerweise die Sockets nur für eine begrenzte Zeit offen hält).
eckes

Antworten:


71

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.


4
Es ist eine gute Idee. Sie müssen nicht haben , aber wenn Sie das nicht tun, dann können Sie nicht einen defekten Link erkennen , bis jemand tatsächlich etwas tun möchte. Was vielleicht eine gute Sache ist oder nicht (oder vielleicht auch nicht), je nachdem, was Sie tatsächlich erreichen wollen.
Matthew Scharley

1
@Pacerier: Hängt vom Protokoll ab, da es vollständig protokollabhängig ist, aber für textbasierte Protokolle, die einen Literal erfordern, sind die Befehle "PING" und "PONG" ziemlich typisch.
Matthew Scharley

4
@MatthewScharley: Dieses "Ping Pong" ist bereits in den Standard-TCP-Implementierungen für uns implementiert und heißt "Keep-Alive" (siehe die andere beliebte Antwort auf diese Frage). Gibt es einen Grund, es auf App-Ebene zu implementieren?
Tim Cooper

7
@ TimCooper: Es ist nicht wirklich. Wie ich in Kommentaren zu anderen Antworten hervorgehoben habe, ist die TCP-Implementierung für die meisten Anforderungen auf Anwendungsebene nicht hilfreich . Sie können keine bei Bedarf senden, und für die meisten Betriebssysteme kann das TCP-Keepalive-Timeout nur auf systemweiter Ebene konfiguriert und viel zu hoch eingestellt werden, um für Anwendungen allgemein nützlich zu sein.
Matthew Scharley

13
@Tim Der Grund für ein Keep-Alive auf Anwendungsebene ist, dass der TCP-Standard empfiehlt, den Keep-Alive-Timer auf mehr als zwei Stunden einzustellen. Ich habe noch nie eine TCP-Verbindung ohne Datenverkehr gesehen, die diesmal überlebt. Daher ist das TCP-Keep-Alive-Zeug standardmäßig nutzlos.
Robert

91

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.

Einführung

TCP-Verbindungen bestehen aus zwei Sockets, einer an jedem Ende der Verbindung. Wenn eine Seite die Verbindung beenden möchte, sendet sie ein RSTPaket, 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.

Keep-Alive-Prozess

Es gibt drei konfigurierbare Eigenschaften, die bestimmen, wie Keep-Alives funktionieren. Unter Linux sind sie 1 :

  • tcp_keepalive_time
    • Standard 7200 Sekunden
  • tcp_keepalive_probes
    • Standard 9
  • tcp_keepalive_intvl
    • Standard 75 Sekunden

Der Prozess funktioniert folgendermaßen:

  1. Client öffnet TCP-Verbindung
  2. Wenn die Verbindung für tcp_keepalive_timeSekunden still ist , senden Sie ein einzelnes leeres ACKPaket. 1
  3. Hat der Server mit einem eigenen Korrespondenten ACKgeantwortet?
    • Nein
      1. Warten Sie tcp_keepalive_intvlSekunden und senden Sie dann eine weitereACK
      2. Wiederholen Sie diesen Vorgang, bis die Anzahl der ACKgesendeten Sonden gleich ist tcp_keepalive_probes.
      3. Wenn zu diesem Zeitpunkt noch keine Antwort eingegangen ist, senden Sie eine RSTund beenden Sie die Verbindung.
    • Ja : Kehren Sie zu Schritt 2 zurück

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.

Fallstricke

2 Stunden Standard

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.

Keep-Alive ist optional

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.

Ändern von TCP-Zeitüberschreitungen

Pro Sockel

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.

Linux

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

Mac OS X

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 keepidleund keepintvlin Millisekunden im Gegensatz zu Linux, das Sekunden verwendet.

Es können die Eigenschaften festgelegt werden, mit sysctldenen 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

Windows

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 tcpWeitere 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 ACKPaket. 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 .


Sehr hilfreich, danke! Ein Zusatz: Für Windows ist ein Neustart erforderlich, damit neue Werte von KeepAliveTime wirksam werden.
Geld0r

Unter AIX können aktuelle TCP Keep-Alive-Einstellungen mit dem $ no -a | grep tcp_keepBefehl abgefragt werden .
Jarek Przygódzki

55

Sie suchen nach der Socket-Option SO_KEEPALIVE.

Die Java Socket-API macht Anwendungen über die Methoden setKeepAliveund 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.


4
Wenn ich ein setKeepAlive (true); Was wäre das Intervall? ... wird Java auch weiterhin Keep-Alive-Nachrichten im Standardintervall senden oder muss ich dies programmgesteuert tun?
Kevin Boyd

3
unixguide.net/network/socketfaq/4.7.shtml Enthält eine Beschreibung von SO_KEEPALIVE. Es ist nicht so sehr , was die OP wollte, obwohl es ist ein Protokoll basierte Option zu dem, was ich vorgeschlagen ... obwohl, einmal alle zwei Stunden werden nicht viel für Anwendungen tun.
Matthew Scharley

4
@MatthewScharley In Bezug auf „darf es nicht standardmäßig auf nicht weniger als zwei Stunden“ ... Mittel es erlaubt ist , weniger als zwei Stunden richtig?
Pacerier

1
@MatthewScharley - "Sie haben Recht, aber das wäre implementierungsspezifisch ..." . Ein Keep-Alive-Intervall, das nicht weniger als zwei Stunden betragen könnte, wäre so nutzlos, dass es schwer vorstellbar ist, dass jemand es implementiert.
Stephen C

2
@ Daniel - die Alternative (in Java) wäre, manuell am Leben zu bleiben, wie oben und in anderen Antworten erwähnt. Nicht schön, aber vielleicht besser als eine betriebssystemweite Änderung der Standardeinstellung, die Systemdienste oder andere Anwendungen beschädigen könnte .
Stephen C

33

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.


2
Sie können das TCP-Keepalive-Intervall an Ihre Anwendung anpassen. ZB msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx
Dan Berindei

@ZZCoder Können Sie erläutern, was es bedeutet, wenn Sie sagen "Keepalive bedeutet in HTTP den dauerhaften Verbindungsstatus"?
Pacerier

1
@Pacerier: Bei HTTP/1.0jeder Anfrage / Antwort musste erneut eine Verbindung zum Server hergestellt werden. Denn HTTP/1.1sie führten einen Keep-AliveHeader 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.
Matthew Scharley

Dies bedeutet im Grunde, dass viele HTTP-Anfragen dieselbe TCP-Verbindung wiederverwenden werden / sollten (Diese Verbindungen haben möglicherweise auch Keep-Alive, werden jedoch nicht auf HTTP gemessen, sodass es sich im Wesentlichen um ein anderes Konzept handelt).
Igor Čordaš

23

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.


Ah! Sie fügen hier einen guten Punkt hinzu, das heißt, Sie müssen auch die dazwischen liegenden Dinge berücksichtigen, die den Betrieb einer Verbindung behindern könnten, wie z. B. NAT-Router usw.
Kevin Boyd

4
Dies ist ein guter Punkt und eine gute Erinnerung daran, dass es mehr zu beachten gibt als nur das, was wir direkt selbst implementieren. Auch Lemminge !!
Matthew Scharley

Beachten Sie, dass die gemeinsame Nutzung von P2P-Dateien viele Ports zerkaut und viele Zombie-Verbindungen erzeugt, wodurch es wahrscheinlicher wird, dass der NAT inaktive Verbindungen entfernen muss.
Artelius

4
Nicht unbedingt wird eine TCP-Verbindung durch 4 Elemente identifiziert: src ip, src port, dest ip, dest port. Sie können also denselben externen (Quell-) Port wiederverwenden, solange die Ziel-IP unterschiedlich ist.
Dan Berindei

1
Oh ja, du hast recht. Ich denke, der wahre Grund ist, dass NATs aufgrund von Speicherbeschränkungen und Nachschlagezeiten eine Tabelle mit offenen Verbindungen mit fester Größe haben.
Artelius

4

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.


1

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.


0

Für Windows gemäß Microsoft-Dokumenten

  • KeepAliveTime (REG_DWORD, Millisekunden, standardmäßig nicht festgelegt, was 7.200.000.000 = 2 Stunden bedeutet) - analog zu tcp_keepalive_time
  • KeepAliveInterval (REG_DWORD, Millisekunden, standardmäßig nicht festgelegt, was 1.000 = 1 Sekunde bedeutet) - analog zu tcp_keepalive_intvl
  • Da es unter Windows Vista kein Analogon zu tcp_keepalive_probes gibt, ist der Wert auf 10 festgelegt und kann nicht geändert werden
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.