Socket schließen oder herunterfahren?

Lesezeit: 9 Minuten

In C habe ich verstanden, dass das Schließen eines Sockets bedeutet, dass der Socket zerstört wird und später wiederverwendet werden kann.

Wie wäre es mit einer Abschaltung? Die Beschreibung besagt, dass es die Hälfte einer Duplex-Verbindung zu dieser Buchse schließt. Aber wird diese Steckdose zerstört werden? close Systemaufruf?

  • Es kann später nicht wiederverwendet werden. Es ist geschlossen. Fertig. Fertig.

    – Benutzer207421

    1. Februar 2020 um 10:06 Uhr

Benutzeravatar von Matthew Flaschen
Matthäus Flaschen

Das ist erklärt in Beejs Netzwerkleitfaden. shutdown ist eine flexible Möglichkeit, die Kommunikation in eine oder beide Richtungen zu blockieren. Wenn der zweite Parameter ist SHUT_RDWRblockiert es sowohl das Senden als auch das Empfangen (wie close). Jedoch, close ist der Weg, eine Steckdose tatsächlich zu zerstören.

Mit shutdownkönnen Sie weiterhin ausstehende Daten empfangen, die der Peer bereits gesendet hat (danke an Joey Adams für diesen Hinweis).

  • Denken Sie daran, selbst wenn Sie einen TCP-Socket schließen (), ist er nicht unbedingt sofort wiederverwendbar, da er sich in einem TIME_WAIT-Zustand befindet, während das Betriebssystem sicherstellt, dass keine ausstehenden Pakete vorhanden sind, die bei Ihnen als neue Informationen verwechselt werden könnten diese Steckdose sofort für etwas anderes wiederverwenden würden.

    – Alesplin

    11. November 2010 um 23:46 Uhr


  • Der große Unterschied zwischen Herunterfahren und Schließen eines Sockets ist das Verhalten, wenn der Socket von anderen Prozessen gemeinsam genutzt wird. Ein shutdown() wirkt alle Kopien des Sockets, während close() nur den Dateideskriptor in einem Prozess beeinflusst.

    – Zan Luchs

    12. November 2010 um 0:24 Uhr

  • Ein Grund, den Sie vielleicht verwenden möchten shutdown beide Richtungen aber nicht close ist, wenn Sie a gemacht haben FILE Verweis auf den Socket mit fdopen. Wenn du close der socket, einer neu geöffneten datei könnte dieselbe fd zugewiesen werden, und die anschließende verwendung der FILE liest/schreibt an der falschen Stelle, was sehr schlimm sein kann. Wenn Sie gerade shutdownnachfolgende Verwendung der FILE wird nur Fehler bis geben fclose wird genannt.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    12. November 2010 um 4:22 Uhr

  • Der Kommentar zu TIME_WAIT ist falsch. Das gilt für Ports, nicht für Sockets. Sie können Sockets nicht wiederverwenden.

    – Benutzer207421

    12. November 2010 um 8:53 Uhr


  • -1. Sowohl dieser Beitrag als auch der Link lassen einen wichtigen konzeptionellen Grund für die Verwendung aus shutdown: um dem Peer EOF zu signalisieren und trotzdem anhängige Daten empfangen zu können, die der Peer gesendet hat.

    – Joey Adams

    13. Januar 2013 um 23:39 Uhr

Benutzeravatar von Earth Engine
Erde-Motor

Keine der vorhandenen Antworten sagt den Leuten, wie shutdown und close arbeitet auf TCP-Protokollebene, daher lohnt es sich, dies hinzuzufügen.

Eine Standard-TCP-Verbindung wird durch 4-Wege-Finalisierung beendet:

  1. Sobald ein Teilnehmer keine Daten mehr zu senden hat, sendet er ein FIN-Paket an den anderen
  2. Die andere Partei sendet eine ACK für die FIN zurück.
  3. Wenn die andere Partei ebenfalls die Datenübertragung beendet hat, sendet sie ein weiteres FIN-Paket
  4. Der anfängliche Teilnehmer sendet eine ACK zurück und schließt die Übertragung ab.

Es gibt jedoch eine andere “emergente” Möglichkeit, eine TCP-Verbindung zu schließen:

  1. Ein Teilnehmer sendet ein RST-Paket und bricht die Verbindung ab
  2. Die andere Seite empfängt ein RST und bricht die Verbindung dann ebenfalls ab

In meinem Test mit Wireshark, mit Standard-Socket-Optionen, shutdown sendet ein FIN-Paket an das andere Ende, aber es ist alles, was es tut. Bis die andere Partei Ihnen das FIN-Paket sendet, können Sie weiterhin Daten empfangen. Sobald dies geschehen ist, Ihre Receive wird ein Ergebnis der Größe 0 erhalten. Wenn Sie also der Erste sind, der “Senden” beendet, sollten Sie den Socket schließen, sobald Sie mit dem Empfangen von Daten fertig sind.

Andererseits, wenn Sie anrufen close Solange die Verbindung noch aktiv ist (die andere Seite ist noch aktiv und Sie haben möglicherweise auch nicht gesendete Daten im Systempuffer), wird ein RST-Paket an die andere Seite gesendet. Das ist gut für Fehler. Wenn Sie beispielsweise der Meinung sind, dass die andere Partei falsche Daten bereitgestellt hat oder die Bereitstellung von Daten verweigert hat (DOS-Angriff?), können Sie den Socket sofort schließen.

Meine Meinung zu Regeln wäre:

  1. In Betracht ziehen shutdown Vor close wenn möglich
  2. Wenn Sie den Empfang beendet haben (Datengröße 0 empfangen), bevor Sie sich für das Herunterfahren entschieden haben, schließen Sie die Verbindung, nachdem der letzte Sendevorgang (falls vorhanden) abgeschlossen wurde.
  3. Wenn Sie die Verbindung normal schließen möchten, beenden Sie die Verbindung (mit SHUT_WR, und wenn Sie nach diesem Punkt keine Daten empfangen möchten, auch mit SHUT_RD), und warten Sie, bis Sie Daten der Größe 0 erhalten, und schließen Sie dann die Steckdose.
  4. In jedem Fall schließen Sie einfach den Socket, wenn ein anderer Fehler aufgetreten ist (z. B. Zeitüberschreitung).

Ideale Implementierungen für SHUT_RD und SHUT_WR

Das Folgende wurde nicht getestet, vertrauen Sie auf eigene Gefahr. Ich glaube jedoch, dass dies ein vernünftiger und praktischer Weg ist, Dinge zu tun.

Wenn der TCP-Stack nur mit SHUT_RD heruntergefahren wird, soll er diese Verbindung als keine weiteren Daten erwartet markieren. Alle ausstehenden und nachfolgenden read Anfragen (egal in welchem ​​Thread sie sich befinden) werden dann mit einem Ergebnis der Größe Null zurückgegeben. Die Verbindung ist jedoch weiterhin aktiv und nutzbar – Sie können beispielsweise weiterhin OOB-Daten empfangen. Außerdem löscht das Betriebssystem alle Daten, die es für diese Verbindung empfängt. Aber das ist alles, es werden keine Pakete auf die andere Seite geschickt.

Wenn der TCP-Stack nur mit SHUT_WR heruntergefahren wird, soll er diese Verbindung markieren, da keine Daten mehr gesendet werden können. Alle ausstehenden Schreibanforderungen werden abgeschlossen, aber nachfolgende Schreibanforderungen werden fehlschlagen. Außerdem wird ein FIN-Paket an eine andere Seite gesendet, um sie darüber zu informieren, dass wir keine weiteren Daten zu senden haben.

  • “if you call close while the connection still alive” ist tautologisch und bewirkt nicht, dass ein RST gesendet wird. (1) ist nicht erforderlich. In (4) sind Zeitüberschreitungen nicht unbedingt fatal für die Verbindung und zeigen nicht immer an, dass Sie sie schließen können.

    – Benutzer207421

    6. Mai 2014 um 0:32 Uhr

  • @EJP Nein, es ist nicht tautologisch. Du kannst shutdown() die Verbindung und dann ist es nicht mehr am Leben. Sie haben immer noch den Dateideskriptor. Du kannst immernoch recv() aus dem Empfangspuffer. Und Sie müssen noch anrufen close() um den Dateideskriptor zu entsorgen.

    – Pavel Simerda

    21. Januar 2016 um 9:58 Uhr

  • Dies ist die beste Antwort in Bezug auf das Drahtformat. Ich wäre an weiteren Details zum Herunterfahren mit SHUT_RD interessiert. Es gibt keine TCP-Signalisierung, um nicht mehr Daten zu erwarten, richtig? Gibt es nicht nur FIN zum Signalisieren, dass keine weiteren Daten gesendet werden?

    – Pavel Simerda

    24. Januar 2016 um 13:36 Uhr

  • @PavelŠimerda Ja TCP signalisiert nicht, dass keine weiteren Daten erwartet werden. Dies sollte in den High-Level-Protokollen berücksichtigt werden. Meiner Meinung nach ist dies im Allgemeinen nicht erforderlich. Sie können Ihre Tür schließen, aber Sie können die Leute nicht daran hindern, Geschenke vor die Tür zu stellen. Das ist IHRE Entscheidung, nicht deine.

    – Erdmotor

    31. Mai 2016 um 22:29 Uhr

  • @EJP Haben Sie irgendwelche tatsächlichen Argumente? Sonst interessiert es mich nicht.

    – Pavel Simerda

    10. November 2016 um 22:41 Uhr

Benutzeravatar von Milan
Mailand

Es gibt einige Einschränkungen mit close() das kann man vermeiden wenn man verwendet shutdown() stattdessen.

close() beendet beide Richtungen einer TCP-Verbindung. Manchmal möchten Sie dem anderen Endpunkt mitteilen, dass Sie mit dem Senden von Daten fertig sind, aber dennoch Daten empfangen möchten.

close() dekrementiert den Deskriptor-Referenzzähler (wird im Dateitabelleneintrag verwaltet und zählt die Anzahl der derzeit geöffneten Deskriptoren, die auf eine Datei/einen Socket verweisen) und schließt den Socket/die Datei nicht, wenn der Deskriptor nicht 0 ist. Das bedeutet, wenn Sie forken, Die Bereinigung erfolgt erst, nachdem der Referenzzähler auf 0 gefallen ist. Mit shutdown() man kann eine normale TCP-Close-Sequenz initiieren, indem man den Referenzzähler ignoriert.

Parameter sind wie folgt:

int shutdown(int s, int how); // s is socket descriptor

int how kann sein:

SHUT_RD oder 0
Weitere Empfangen sind nicht erlaubt

SHUT_WR oder 1
Weitere Sendungen sind nicht erlaubt

SHUT_RDWR oder 2
Weiteres Senden und Empfangen ist nicht erlaubt

  • Die beiden Funktionen dienen völlig unterschiedlichen Zwecken. Die Tatsache, dass das abschließende Schließen eines Sockets eine Shutdown-Sequenz einleitet, wenn noch keine initiiert wurde, ändert nichts an der Tatsache, dass close zum Bereinigen der Socket-Datenstrukturen dient und shutdown zum Einleiten einer Shutdown-Sequenz auf TCP-Ebene dient.

    – Len Holgate

    12. November 2010 um 10:08 Uhr

  • Sie können nicht ‘stattdessen Shutdown verwenden’. Du kannst es benutzen auch. aber Sie müssen den Socket irgendwann schließen.

    – Benutzer207421

    13. November 2010 um 0:44 Uhr

Benutzeravatar von Len Holgate
Len Holgate

Das mag plattformspezifisch sein, ich bezweifle es irgendwie, aber wie auch immer, die beste Erklärung, die ich gesehen habe, ist hier auf dieser MSDN-Seite wo sie das Herunterfahren, Verweiloptionen, das Schließen von Sockets und allgemeine Sequenzen zum Beenden von Verbindungen erklären.

Zusammenfassend lässt sich sagen, dass Sie mit shutdown eine Sequenz zum Herunterfahren auf TCP-Ebene senden und mit close die Ressourcen freigeben, die von den Socket-Datenstrukturen in Ihrem Prozess verwendet werden. Wenn Sie zum Zeitpunkt des Aufrufs von close keine explizite Abschaltsequenz ausgegeben haben, wird eine für Sie initiiert.

Ich hatte auch Erfolg unter Linux mit shutdown() von einem pthread, um einen anderen pthread zu erzwingen, der derzeit blockiert ist connect() vorzeitig abzubrechen.

Unter anderen Betriebssystemen (zumindest OSX) fand ich Aufrufe close() war genug zu bekommen connect() scheitern.

“shutdown() schließt den Dateideskriptor nicht wirklich – es ändert nur seine Benutzerfreundlichkeit. Um einen Socket-Deskriptor freizugeben, müssen Sie close() verwenden.”1

Benutzeravatar von JJ Hakala
JJ Hakala

Nah dran

Wenn Sie mit der Verwendung eines Sockets fertig sind, können Sie seinen Dateideskriptor einfach mit close schließen; Wenn noch Daten darauf warten, über die Verbindung übertragen zu werden, versucht normalerweise close, diese Übertragung abzuschließen. Sie können dieses Verhalten steuern, indem Sie die Socket-Option SO_LINGER verwenden, um eine Zeitüberschreitung anzugeben. siehe Socket-Optionen.

Stilllegen

Sie können auch nur den Empfang oder die Übertragung auf einer Verbindung beenden, indem Sie shutdown aufrufen.

Die Shutdown-Funktion beendet die Verbindung der Steckdose. Sein Argument how gibt an, welche Aktion ausgeführt werden soll: 0 Beende den Empfang von Daten für diesen Socket. Wenn weitere Daten eintreffen, lehnen Sie diese ab. 1 Hören Sie auf, Daten von diesem Socket zu übertragen. Verwerfen Sie alle Daten, die darauf warten, gesendet zu werden. Hören Sie auf, nach einer Bestätigung für bereits gesendete Daten zu suchen; Übertragen Sie es nicht erneut, wenn es verloren geht. 2 Stoppen Sie sowohl den Empfang als auch die Übertragung.

Der Rückgabewert ist 0 bei Erfolg und -1 bei Misserfolg.

1426150cookie-checkSocket schließen oder herunterfahren?

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

Privacy policy