it-swarm.com.de

vs Steckdose schließen?

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? 

181
hdn

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).

163

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:

  1. Sobald ein Teilnehmer keine Daten mehr zu senden hat, sendet er ein FIN-Paket an den anderen
  2. Die Gegenpartei gibt eine ACK für die FIN zurück.
  3. Wenn die Gegenstelle auch die Datenübertragung abgeschlossen hat, sendet sie ein weiteres FIN-Paket
  4. Der erste Teilnehmer gibt eine ACK zurück und schließt die Übertragung ab.

Es gibt jedoch eine andere "aufkommende" Methode, um 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 ebenfalls ab

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:

  1. Berücksichtigen Sie, falls möglich, shutdown vor close
  2. Wenn Sie mit dem Empfang der Daten (Größe 0) fertig sind, bevor Sie sich für das Herunterfahren entschieden haben, schließen Sie die Verbindung, nachdem der letzte Sendevorgang (falls vorhanden) beendet wurde.
  3. Wenn Sie die Verbindung normal beenden möchten, beenden Sie die Verbindung (mit SHUT_WR und wenn Sie nach diesem Punkt keine Daten mehr empfangen möchten, auch mit SHUT_RD). Warten Sie, bis Sie Daten der Größe 0 erhalten, und schließen Sie dann die Steckdose.
  4. 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 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.

110
Earth Engine

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

33
Milan

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.

15
Len Holgate

"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.

7
Toby

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.

3
Neha Agrawal

in meinem Test.

close sendet ein fin-Paket und zerstört fd sofort, wenn der Socket nicht mit anderen Prozessen geteilt wird

shutdownSHUT_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.

shutdownSHUT_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

shutdownSHUT_RDWR (gleichbedeutend mit SHUT_RD und SHUT_WR) sendet das erste Paket, wenn Peer mehr Daten sendet.

2
simpx