Linux Socket: Wie erkennt man ein getrenntes Netzwerk in einem Client-Programm?

Lesezeit: 5 Minuten

Ich debugge ein ac-basiertes Linux-Socket-Programm. Wie alle auf Websites verfügbaren Beispiele habe ich die folgende Struktur angewendet:

sockfd= socket(AF_INET, SOCK_STREAM, 0);

connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

send_bytes = send(sockfd, sock_buff, (size_t)buff_bytes, MSG_DONTWAIT);

Ich kann die Trennung erkennen, wenn der Entfernungsserver sein Serverprogramm schließt. Aber wenn ich das Ethernet-Kabel abziehe, gibt die Sendefunktion immer noch positive Werte statt -1 zurück.

Wie kann ich die Netzwerkverbindung in einem Client-Programm überprüfen, vorausgesetzt, ich kann die Serverseite nicht ändern?

Aber wenn ich das Ethernet-Kabel abziehe, gibt die Sendefunktion immer noch positive Werte statt -1 zurück.

Zunächst einmal sollten Sie wissen send sendet eigentlich nichts, es ist nur eine Speicherkopierfunktion/ein Systemaufruf. Es kopiert Daten von Ihrem Prozess in den Kernel – einige Zeit später holt der Kernel diese Daten und sendet sie an die andere Seite, nachdem er sie in Segmente und Pakete verpackt hat. Deshalb send kann nur einen Fehler zurückgeben, wenn:

  • Der Socket ist ungültig (z. B. falscher Dateideskriptor)
  • Die Verbindung ist eindeutig ungültig, zum Beispiel wurde sie nicht hergestellt oder wurde bereits auf irgendeine Weise beendet (FIN, RST, Timeout – siehe unten).
  • Es gibt keinen Platz mehr, um die Daten zu kopieren

Der Hauptpunkt ist das send sendet nichts und daher sein Rückkehrcode sagt nichts darüber aus, ob Daten tatsächlich die andere Seite erreichen.

Zurück zu Ihrer Frage: Wenn TCP Daten sendet, erwartet es in angemessener Zeit eine gültige Bestätigung. Wenn es keine erhält, wird es erneut gesendet. Wie oft wird es erneut gesendet? Jeder TCP-Stack macht die Dinge anders, aber die Norm ist die Verwendung exponentieller Backoffs. Das heißt, warten Sie zuerst 1 Sekunde, dann 2, dann 4 und so weiter. Bei manchen Stacks kann dieser Vorgang Minuten dauern.

Der Hauptpunkt ist, dass TCP im Falle einer Unterbrechung eine Verbindung für tot erklärt erst nach einer ernsthaft langen Zeit des Schweigens (unter Linux macht es ungefähr 15 Wiederholungen – mehr als 5 Minuten).

Eine Möglichkeit, dies zu lösen, besteht darin, einen Bestätigungsmechanismus in Ihrer Anwendung zu implementieren. Sie könnten zum Beispiel eine Anfrage an den Server senden “Antworten Sie innerhalb von 5 Sekunden oder ich erkläre diese Verbindung für tot” und dann recv mit Zeitüberschreitung.

Benutzeravatar von Forhad Ahmed
Forhad Ahmed

Gehen Sie wie folgt vor, um eine Remote-Trennung zu erkennen read()

Überprüfen Sie diesen Thread für weitere Informationen:

Kann die Funktion read() auf einem verbundenen Socket Null Bytes zurückgeben?

  • Die Frage bezieht sich auf das Abziehen des Ethernet-Kabels.

    – Benutzer207421

    25. Januar 2016 um 11:20 Uhr

Benutzeravatar von cloudrain21
Wolkenregen21

Sie können das nicht angeschlossene Ethernet-Kabel nur mit dem Aufruf der Funktion write() erkennen. Das liegt an der TCP-Neuübertragung, die vom TCP-Stack ohne Ihr Bewusstsein ausgeführt wird. Hier sind Lösungen.

Obwohl Sie die Keepalive-Option bereits für Ihren Anwendungs-Socket festgelegt haben, können Sie den toten Verbindungsstatus des Sockets nicht rechtzeitig erkennen, falls Ihre App weiterhin auf den Socket schreibt. Das liegt an der TCP-Neuübertragung durch den Kernel-TCP-Stack. tcp_retries1 und tcp_retries2 sind Kernelparameter zum Konfigurieren des TCP-Retransmission-Timeouts. Es ist schwierig, den genauen Zeitpunkt des Timeouts für die erneute Übertragung vorherzusagen, da er vom RTT-Mechanismus berechnet wird. Sie können diese Berechnung in rfc793 sehen. (3.7. Datenkommunikation)

https://www.rfc-editor.org/rfc/rfc793.txt

Jede Plattform hat Kernel-Konfigurationen für TCP-Neuübertragung.

Linux : tcp_retries1, tcp_retries2 : (exist in /proc/sys/net/ipv4)

http://linux.die.net/man/7/tcp

HPUX : tcp_ip_notify_interval, tcp_ip_abort_interval

http://www.hpuxtips.es/?q=node/53

AIX : rto_low, rto_high, rto_length, rto_limit

http://www-903.ibm.com/kr/event/download/200804_324_swma/socket.pdf

Sie sollten einen niedrigeren Wert für tcp_retries2 (Standard 15) festlegen, wenn Sie tote Verbindungen frühzeitig erkennen möchten, aber es ist keine genaue Zeit, wie ich bereits sagte. Darüber hinaus können Sie diese Werte derzeit nicht nur für einzelne Sockets festlegen. Das sind globale Kernel-Parameter. Es gab einige Versuche, die TCP-Retransmission-Socket-Option für Single Socket anzuwenden (http://patchwork.ozlabs.org/patch/55236/), aber ich glaube nicht, dass es in die Kernel-Hauptlinie übernommen wurde. Ich kann diese Optionsdefinition in den Systemheaderdateien nicht finden.

Als Referenz können Sie Ihre Keepalive-Socket-Option über „netstat –timers“ wie unten überwachen. https://stackoverflow.com/questions/34914278

netstat -c --timer | grep "192.0.0.1:43245             192.0.68.1:49742"

tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (1.92/0/0)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (0.71/0/0)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (9.46/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (8.30/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (7.14/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (5.98/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (4.82/0/1)

Darüber hinaus können Sie bei einer Keepalive-Zeitüberschreitung je nach verwendeter Plattform auf unterschiedliche Rückgabeereignisse treffen, sodass Sie den Status einer toten Verbindung nicht nur anhand von Rückgabeereignissen bestimmen müssen. Beispielsweise gibt HP das Ereignis POLLERR und AIX nur das Ereignis POLLIN zurück, wenn das Keepalive-Timeout auftritt. Sie werden zu diesem Zeitpunkt auf den ETIMEDOUT-Fehler im Aufruf von recv() stoßen.

In der neueren Kernel-Version (seit 2.6.37) können Sie die Option TCP_USER_TIMEOUT verwenden, die gut funktioniert. Diese Option kann für eine einzelne Steckdose verwendet werden.

Schließlich können Sie die Lesefunktion mit dem MSG_PEEK-Flag verwenden, mit dem Sie überprüfen können, ob der Socket in Ordnung ist. (MSG_PEEK schaut nur, ob Daten im Kernel-Stack-Puffer angekommen sind, und kopiert die Daten niemals in den Benutzerpuffer.) Sie können dieses Flag also nur zum Überprüfen verwenden, ob der Socket ohne Nebenwirkungen in Ordnung ist.

Überprüfen Sie den Rückgabewert und prüfen Sie, ob er diesem Wert entspricht:

EPIPE
Diese Steckdose wurde angeschlossen, aber die Verbindung ist jetzt unterbrochen. In diesem Fall erzeugt send zuerst ein SIGPIPE-Signal; Wenn dieses Signal ignoriert oder blockiert wird oder wenn sein Handler zurückkehrt, schlägt das Senden mit EPIPE fehl.

Fügen Sie auch eine Überprüfung für das SIGPIPE-Signal in Ihrem Handler hinzu, um es kontrollierbarer zu machen.

1444090cookie-checkLinux Socket: Wie erkennt man ein getrenntes Netzwerk in einem Client-Programm?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy