Keine der vorhandenen Antworten sagt den Leuten, wie shutdown
und close
auf TCP-Protokollebene funktioniert, daher lohnt es sich, dies hinzuzufügen.
Eine Standard-TCP-Verbindung wird durch 4-Wege-Finalisierung beendet:
- Sobald ein Teilnehmer keine Daten mehr zu senden hat, sendet er ein FIN-Paket an den anderen
- Die andere Partei gibt eine Bestätigung für die FIN zurück.
- Wenn der andere Teilnehmer auch die Datenübertragung beendet hat, sendet er ein weiteres FIN-Paket
- Der ursprüngliche Teilnehmer gibt eine Bestätigung zurück und schließt die Übertragung ab.
Es gibt jedoch eine andere "emergente" Möglichkeit, eine TCP-Verbindung zu schließen:
- Ein Teilnehmer sendet ein RST-Paket und bricht die Verbindung ab
- Die andere Seite erhält eine RST und bricht dann ebenfalls die Verbindung ab
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:
- Überlegen Sie
shutdown
vorher, close
wann immer dies möglich ist
- Wenn Sie den Empfang abgeschlossen haben (Daten der Größe 0 empfangen), bevor Sie sich zum Herunterfahren entschieden haben, schließen Sie die Verbindung nach dem letzten Senden (falls vorhanden).
- Wenn Sie die Verbindung normal schließen möchten, beenden Sie die Verbindung (mit SHUT_WR, und wenn Sie nach diesem Zeitpunkt keine Daten mehr empfangen möchten, auch mit SHUT_RD), und warten Sie, bis Sie Daten der Größe 0 erhalten, und schließen Sie dann die Verbindung Steckdose.
- In jedem Fall, wenn ein anderer Fehler aufgetreten ist (z. B. Timeout), schließen Sie einfach den Socket.
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 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.