In C habe ich verstanden, dass wenn wir einen Socket schließen, dies bedeutet, dass der Socket zerstört wird und später wiederverwendet werden kann.
Wie wäre es mit Herunterfahren? Die Beschreibung besagt, dass die Hälfte einer Duplexverbindung zu diesem Socket geschlossen wird. Aber wird dieser Socket wie close
ein Systemaufruf zerstört?
c
sockets
networking
Tshepang
quelle
quelle
Antworten:
Dies wird im Netzwerkhandbuch von Beej erläutert .
shutdown
ist eine flexible Möglichkeit, die Kommunikation in eine oder beide Richtungen zu blockieren. Wenn der zweite Parameter istSHUT_RDWR
, blockiert er sowohl das Senden als auch das Empfangen (wieclose
). Diesclose
ist jedoch der Weg, um eine Steckdose tatsächlich zu zerstören.Mit
shutdown
können Sie weiterhin ausstehende Daten empfangen, die der Peer bereits gesendet hat (danke an Joey Adams, der dies bemerkt hat).quelle
shutdown
beide Richtungen verwenden möchten, ist jedoch nicht,close
wenn Sie mitFILE
auf die Buchse verwiesen habenfdopen
. Wenn Sieclose
den Socket haben, könnte einer neu geöffneten Datei derselbe fd zugewiesen werden, und die anschließende Verwendung desFILE
wird den falschen Ort lesen / schreiben, was sehr schlecht sein könnte. Wenn Sie nurshutdown
, wird die spätere Verwendung vonFILE
nur Fehler geben, bisfclose
aufgerufen wird.shutdown
: EOF an den Peer zu signalisieren und dennoch ausstehende Daten empfangen zu können, die der Peer gesendet hat.Keine der vorhandenen Antworten sagt den Leuten, wie
shutdown
undclose
auf TCP-Protokollebene funktioniert, daher lohnt es sich, dies hinzuzufügen.Eine Standard-TCP-Verbindung wird durch 4-Wege-Finalisierung beendet:
Es gibt jedoch eine andere "emergente" Möglichkeit, eine TCP-Verbindung zu schließen:
In meinem Test mit Wireshark mit den Standard-Socket-Optionen wird
shutdown
ein FIN-Paket an das andere Ende gesendet, aber es ist alles, was es tut. Bis die andere Partei Ihnen das FIN-Paket sendet, können Sie weiterhin Daten empfangen. Sobald dies passiert ist,Receive
erhalten Sie ein Ergebnis der Größe 0. Wenn Sie also der erste sind, der "Senden" herunterfährt, sollten Sie den Socket schließen, sobald Sie den Datenempfang abgeschlossen haben.Wenn Sie dagegen anrufen,
close
während 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 angegeben hat oder sich geweigert hat, Daten bereitzustellen (DOS-Angriff?), Können Sie den Socket sofort schließen.Meine Meinung zu Regeln wäre:
shutdown
vorher,close
wann immer dies möglich istIdeale 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 Art ist, Dinge zu tun.
Wenn der TCP-Stack nur mit SHUT_RD heruntergefahren wird, markiert er diese Verbindung als keine weiteren erwarteten Daten. Alle ausstehenden und nachfolgenden
read
Anforderungen (unabhängig davon, in welchem Thread sie sich befinden) werden dann mit einem Ergebnis von Null zurückgegeben. Die Verbindung ist jedoch weiterhin aktiv und verwendbar - 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 an die andere Seite gesendet.Wenn der TCP-Stack nur mit SHUT_WR heruntergefahren wird, markiert er diese Verbindung, da keine Daten mehr gesendet werden können. Alle ausstehenden Schreibanforderungen werden beendet, nachfolgende Schreibanforderungen schlagen jedoch fehl. Außerdem wird ein FIN-Paket an eine andere Seite gesendet, um sie darüber zu informieren, dass wir keine weiteren Daten zum Senden haben.
quelle
shutdown()
die Verbindung und dann ist es nicht mehr lebendig. Sie haben noch den Dateideskriptor. Sie können immer nochrecv()
aus dem Empfangspuffer. Und Sie müssen immer noch aufrufenclose()
, um den Dateideskriptor zu entsorgen.Es gibt einige Einschränkungen
close()
, die vermieden werden können, wenn manshutdown()
stattdessen verwendet.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 dennoch Daten empfangen möchten.close()
Verringert die Referenzanzahl der Deskriptoren (wird im Dateitabelleneintrag beibehalten und zählt die Anzahl der aktuell geöffneten Deskriptoren, die sich auf eine Datei / einen Socket beziehen) und schließt den Socket / die Datei nicht, wenn der Deskriptor nicht 0 ist. Die Bereinigung erfolgt erst, nachdem der Referenzzähler auf 0 gefallen ist. Mitshutdown()
kann eine normale TCP-Schließsequenz initiiert werden, wobei der Referenzzähler ignoriert wird.Die Parameter sind wie folgt:
int how
kann sein:SHUT_RD
oder0
Weitere Empfänge sind nicht zulässigSHUT_WR
oder1
Weitere Sendungen sind nicht zulässigSHUT_RDWR
oder2
Weitere Sendungen und Empfänge sind nicht zulässigquelle
Dies mag plattformspezifisch sein, ich bezweifle es irgendwie, aber die beste Erklärung, die ich gesehen habe, ist hier auf dieser MSDN-Seite, wo sie das Herunterfahren, Verweiloptionen, Socket-Schließen und allgemeine Verbindungsbeendigungssequenzen erklären.
Zusammenfassend können Sie mit shutdown eine Shutdown-Sequenz 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 noch keine explizite Abschaltsequenz ausgegeben haben, wird eine für Sie initiiert.
quelle
Ich hatte auch Erfolg unter Linux mit
shutdown()
einem Pthread, um einen anderen derzeit blockierten Pthread zu zwingenconnect()
, vorzeitig abzubrechen.Unter anderen Betriebssystemen (zumindest OSX) fand ich, dass das Anrufen
close()
ausreichte, umconnect()
fehlzuschlagen.quelle
"shutdown () schließt den Dateideskriptor nicht wirklich - es ändert nur seine Verwendbarkeit. Um einen Socket-Deskriptor freizugeben, müssen Sie close () verwenden." 1
quelle
Schließen
Wenn Sie einen Socket nicht mehr verwenden, können Sie den Dateideskriptor einfach mit close schließen. Wenn immer noch Daten auf die Übertragung über die Verbindung warten, versucht normalerweise close, diese Übertragung abzuschließen. Sie können dieses Verhalten mithilfe der Socket-Option SO_LINGER steuern, um eine Zeitüberschreitungsperiode anzugeben. Siehe Socket-Optionen.
Herunterfahren
Sie können auch nur den Empfang oder die Übertragung einer Verbindung beenden, indem Sie shutdown aufrufen.
Die Abschaltfunktion unterbricht die Verbindung der Steckdose. Das Argument, wie angegeben wird, welche Aktion ausgeführt werden soll: 0 Stoppen Sie den Empfang von Daten für diesen Socket. Wenn weitere Daten eingehen, lehnen Sie diese ab. 1 Versuchen Sie nicht mehr, Daten von diesem Socket zu übertragen. Verwerfen Sie alle Daten, die darauf warten, gesendet zu werden. Suchen Sie nicht mehr nach einer Bestätigung der bereits gesendeten Daten. Ü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 Fehler.
quelle
in meinem Test.
close
sendet ein fin-Paket und zerstört fd sofort, wenn der Socket nicht mit anderen Prozessen geteilt wirdshutdown
SHUT_RD , der Prozess kann weiterhin Daten vom Socket abrufen, gibt jedochrecv
0 zurück, wenn der TCP-Puffer leer ist. Nachdem der Peer weitere Daten gesendet hat,recv
werden die Daten erneut zurückgegeben.shutdown
SHUT_WR sendet ein Fin-Paket, um anzuzeigen, dass weitere Sendungen nicht zulässig sind. Der Peer kann Daten empfangen, aber er empfängt 0, wenn sein TCP-Puffer leer istshutdown
SHUT_RDWR (entspricht sowohl SHUT_RD als auch SHUT_WR ) sendet das erste Paket, wenn der Peer mehr Daten sendet.quelle
close()
RST unter Linux anstelle von FIN gesendet.recv()
werden die Daten erneut zurückgegeben' ist nicht korrekt. 2. Das Verhalten, wenn der Peer danach weitere Daten sendet,SHUT_RD
ist plattformabhängig.