In C habe ich verstanden, dass beim Schließen einer Steckdose die Steckdose zerstört wird und später wiederverwendet werden kann.
Wie wäre es mit dem Herunterfahren? Der Beschreibung zufolge wird die Hälfte einer Duplexverbindung zu diesem Sockel geschlossen. Aber wird dieser Socket wie ein Systemaufruf close
zerstört?
Dies ist erklärt im Netzwerkhandbuch von Beej. shutdown
ist eine flexible Möglichkeit, die Kommunikation in eine oder in beide Richtungen zu blockieren. Wenn der zweite Parameter SHUT_RDWR
ist, blockiert er sowohl das Senden als auch das Empfangen (wie close
). Mit close
können Sie jedoch einen Sockel tatsächlich zerstören.
Mit shutdown
können Sie noch ausstehende Daten empfangen, die der Peer bereits gesendet hat (danke an Joey Adams, dass Sie dies bemerkt haben).
Keine der vorhandenen Antworten sagt den Leuten, wie shutdown
und close
auf der Protokollebene TCP funktionieren. Es lohnt sich, dies hinzuzufügen.
Eine Standardverbindung TCP wird durch 4-Wege-Finalisierung beendet:
Es gibt jedoch eine andere "aufkommende" Methode, um eine TCP -Verbindung zu schließen:
In meinem Test mit Wireshark sendet shutdown
mit Standard-Socket-Optionen ein FIN-Paket an das andere Ende, aber es ist alles, was es tut. Bis der andere Teilnehmer Ihnen das FIN-Paket sendet, können Sie noch Daten empfangen. Sobald dies geschehen ist, wird Ihre Receive
ein Ergebnis der Größe 0 erhalten. Wenn Sie also als erster "send" beenden, sollten Sie den Socket schließen, sobald Sie mit dem Datenempfang fertig sind.
Wenn Sie dagegen close
aufrufen, während die Verbindung noch aktiv ist (die andere Seite ist noch aktiv und Sie haben möglicherweise noch 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 angegeben hat oder die Bereitstellung von Daten verweigert hat (DOS-Angriff?), Können Sie den Socket sofort schließen.
Meine Meinung zu Regeln wäre:
shutdown
vor close
Ideale Implementierungen für SHUT_RD und SHUT_WR
Folgendes wurde nicht getestet, Vertrauen auf eigenes Risiko. Ich glaube jedoch, dass dies eine vernünftige und praktische Vorgehensweise ist.
Wenn der TCP -Stack nur mit SHUT_RD heruntergefahren wird, muss er diese Verbindung als nicht mehr erwartet markieren. Alle ausstehenden und nachfolgenden read
-Anforderungen (unabhängig davon, in welchem Thread sie sich befinden) werden mit einem Ergebnis von null zurückgegeben. Die Verbindung ist jedoch immer noch aktiv und verwendbar - Sie können beispielsweise weiterhin OOB-Daten empfangen. Das Betriebssystem löscht auch alle Daten, die es für diese Verbindung erhält. Aber das ist alles, es werden keine Pakete an die andere Seite gesendet.
Wenn der TCP -Stack nur mit SHUT_WR heruntergefahren wird, muss er diese Verbindung markieren, da keine Daten mehr gesendet werden können. Alle ausstehenden Schreibanforderungen werden beendet, nachfolgende Schreibanforderungen schlagen jedoch fehl. Darüber hinaus wird ein FIN-Paket an eine andere Seite gesendet, um sie darüber zu informieren, dass nicht mehr Daten zum Senden zur Verfügung stehen.
Es gibt einige Einschränkungen bei close()
, die vermieden werden können, wenn stattdessen shutdown()
verwendet wird.
close()
beendet beide Richtungen bei einer TCP - Verbindung. Manchmal möchten Sie dem anderen Endpunkt mitteilen, dass Sie mit dem Senden der Daten fertig sind, aber trotzdem Daten empfangen möchten.
close()
dekrementiert den Deskriptorenreferenzzähler (wird im Dateitabelleneintrag beibehalten und zählt die Anzahl der aktuell geöffneten Deskriptoren, die auf eine Datei/einen Socket verweisen) und schließt den Socket/die Datei nicht, wenn der Deskriptor nicht 0 ist Die Bereinigung findet erst statt, wenn der Referenzzähler auf 0 fällt. Mit shutdown()
kann eine normale Schließsequenz TCP eingeleitet werden, wobei der Referenzzähler ignoriert wird.
Parameter sind wie folgt:
int shutdown(int s, int how); // s is socket descriptor
int how
kann sein:
SHUT_RD
oder 0
Weitere Einnahmen sind nicht zulässig
SHUT_WR
oder 1
Weitere Sendungen sind nicht zulässig
SHUT_RDWR
oder 2
Weiteres Senden und Empfangen ist nicht zulässig
Dies mag plattformspezifisch sein, ich bezweifle es irgendwie, aber die beste Erklärung, die ich je gesehen habe, ist hier auf dieser Msdn-Seite , in der sie das Herunterfahren, die Linger-Optionen, die Socket-Schließung und allgemeine Verbindungsabbruchsequenzen erklären.
Zusammenfassend können Sie mit shutdown eine Abschaltsequenz auf Ebene TCP senden und close verwenden, um die von den Socketdatenstrukturen in Ihrem Prozess verwendeten Ressourcen freizugeben. Wenn Sie zu dem Zeitpunkt, zu dem Sie close aufrufen, noch keine explizite Shutdown-Sequenz ausgegeben haben, wird eine für Sie initiiert.
"shutdown () schließt den Dateideskriptor nicht wirklich - er ändert lediglich seine Verwendbarkeit. Um einen Socketdeskriptor freizugeben, müssen Sie close () verwenden." 1
Ich hatte auch unter Linux Erfolg mit shutdown()
von einem Pthread, um einen anderen Pthread zu erzwingen, der derzeit in connect()
blockiert ist, um vorzeitig abzubrechen.
Unter anderen Betriebssystemen (mindestens OSX) habe ich festgestellt, dass das Aufrufen von close()
genug war, um connect()
zu versagen.
Schließen
Wenn Sie die Verwendung eines Sockets beendet haben, können Sie den Dateideskriptor einfach mit close schließen. Wenn noch Daten zur Übertragung über die Verbindung warten, versucht close normalerweise, diese Übertragung abzuschließen. Sie können dieses Verhalten mit der Socketoption SO_LINGER steuern, um einen Timeout-Zeitraum anzugeben. siehe Socket-Optionen.
Ausschalten
Sie können auch nur den Empfang oder die Übertragung einer Verbindung durch Aufrufen des Befehls Herunterfahren beenden.
Die Shutdown-Funktion beendet die Verbindung der Socket. Sein Argument how gibt an, welche Aktion ausgeführt werden soll: 0 Stoppen Sie, Daten für diesen Socket zu empfangen. Wenn weitere Daten ankommen, lehnen Sie diese ab. 1 Stoppen Sie den Versuch, Daten von diesem Socket zu übertragen. Verwerfen Sie alle Daten, die auf den Versand warten. Hören Sie auf, nach bereits gesendeten Daten zu suchen; es nicht erneut übertragen, wenn es verloren geht. 2 Stoppen Sie sowohl den Empfang als auch die Übertragung.
Der Rückgabewert ist 0 bei Erfolg und -1 bei Fehlschlag.
in meinem Test.
close
sendet ein fin-Paket und zerstört fd sofort, wenn der Socket nicht mit anderen Prozessen geteilt wird
shutdown
SHUT_RD, Prozess kann immer noch Daten vom Socket empfangen, aber recv
gibt 0 zurück, wenn TCP Puffer leer ist. Nachher Peer sendet weitere Daten, recv
gibt die Daten erneut zurück.
shutdown
SHUT_WR sendet ein Flossenpaket, um anzuzeigen, dass weitere Sendungen nicht zulässig sind. Der Peer kann Daten empfangen, empfängt aber 0, wenn sein TCP Puffer leer ist
shutdown
SHUT_RDWR (gleichbedeutend mit SHUT_RD und SHUT_WR) sendet das erste Paket, wenn Peer mehr Daten sendet.