Gibt es eine Möglichkeit, einen POSIX-Socket zu leeren?

Lesezeit: 9 Minuten

Benutzeravatar von Gordon Wrigley
Gordon Wrigley

Gibt es einen Standardaufruf zum Leeren der Sendeseite eines POSIX-Sockets bis zum entfernten Ende oder muss dies als Teil des Protokolls auf Benutzerebene implementiert werden? Ich sah mich in den üblichen Überschriften um, konnte aber nichts finden.

Benutzeravatar von Fantastory
Fantasiegeschichte

Was ist mit dem Setzen von TCP_NODELAY und dem Zurücksetzen? Wahrscheinlich könnte dies kurz vor dem Senden wichtiger Daten erfolgen oder wenn wir mit dem Senden einer Nachricht fertig sind.

send(sock, "notimportant", ...);
send(sock, "notimportant", ...);
send(sock, "notimportant", ...);
int flag = 1; 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
send(sock, "important data or end of the current message", ...);
flag = 0; 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));

Wie Linux Manpages sagt

TCP_NODELAY … das Setzen dieser Option erzwingt eine explizite Leerung der anstehenden Ausgabe …

Wahrscheinlich wäre es besser, es nach der Nachricht zu setzen, aber ich bin mir nicht sicher, wie es auf anderen Systemen funktioniert

  • Dies sollte zumindest mit Linux funktionieren; Wenn Sie TCP_NODELAY setzen, wird der aktuelle Puffer geleert, der laut den Quellkommentaren sogar geleert werden sollte, wenn TCP_CORK gesetzt ist.

    – Stefan

    25. Mai 2013 um 13:29 Uhr

  • Ich bestätige, dass es funktioniert. Ich ziehe es vor, TCP_DELAY nach dem Senden der “wichtigen Daten oder des Endes der aktuellen Nachricht” zu setzen und zurückzusetzen, weil es erlaubt, dieses Zeug in eine Flush-Socket-Methode zu stecken.

    – mpromonet

    20. März 2014 um 21:33 Uhr

  • Sie beschreiben eine Situation, in der “unwichtige” Nachrichten mit Nachrichten vermischt werden, die so schnell wie möglich gesendet werden sollen. Ich denke, dass Ihre Lösung für diese Situation eine gute Möglichkeit ist, die Verzögerung zu umgehen, die von Nagle eingeführt werden könnte. Wenn Sie jedoch nicht mehrere Nachrichten, sondern eine zusammengesetzte Nachricht senden, sollten Sie sie mit einer einzigen senden send() Anruf! Denn auch bei Nagle wird das erste Paket sofort verschickt. Nur nachfolgende werden verzögert, und sie werden nur verzögert, bis der Server bestätigt oder antwortet. Also einfach “alles” in den Ersten packen send().

    – Hagello

    24. Juni 2018 um 12:09 Uhr


  • Es stimmt, aber in diesem Fall wissen wir weder, wie groß unwichtige Daten sind, noch ob es Verzögerungen zwischen einzelnen Sendungen gab. Das Problem tritt auf, wenn Daten in eine Richtung gesendet werden. Zum Beispiel arbeite ich als Proxy – ich leite alles weiter, was ich bekomme, und leite es weiter, damit das Netzwerk es optimal sendet, also ist es mir egal. Doch dann kommt ein wichtiges Paket, das ich schnellstmöglich abschicken möchte. Das verstehe ich unter Spülung.

    – Fantasiegeschichte

    18. März 2019 um 14:59 Uhr


Benutzeravatar von chaos
Chaos

Für Unix-Domänen-Sockets können Sie verwenden fflush(), aber ich denke, Sie meinen wahrscheinlich Netzwerk-Sockets. Es gibt nicht wirklich ein Konzept, diese zu spülen. Die nächsten Dinge sind:

  1. Am Ende Ihrer Sitzung rufen Sie an shutdown(sock, SHUT_WR) um Schreibvorgänge auf dem Socket zu schließen.

  2. Deaktivieren Sie bei TCP-Sockets den Nagle-Algorithmus mit sockopt TCP_NODELAYwas im Allgemeinen eine schreckliche Idee ist, die nicht zuverlässig das tut, was Sie wollen, selbst wenn es sich bei der ersten Untersuchung darum zu kümmern scheint.

Es ist sehr wahrscheinlich, dass die Behandlung eines beliebigen Problems, das eine „Flush“ auf Benutzerprotokollebene erfordert, das Richtige sein wird.

  • Ich sehe keinen Grund, warum das Deaktivieren des Nagle-Algorithmus “im Allgemeinen eine schreckliche Idee ist”. Wenn Sie wissen, was es tut, gibt es viele Anwendungsprotokollsituationen, in denen das Deaktivieren von Nagle genau das ist, was Sie tun möchten. Ich vermute, Sie hatten keine Situation, in der Sie das wirklich tun mussten, oder Sie verstehen nicht, was es wirklich tut. Mit anderen Worten, diese Funktion hat einen Grund und kann auch aus einem sehr guten Grund deaktiviert werden.

    – Großer Jeff

    13. Mai 2009 um 1:21 Uhr

  • Sie müssen #include <linux/tcp.h> oder was auch immer die Include-Datei bereitstellt TCP_NODELAY auf Ihrem System (versuchen Sie es fgrep -r 'define TCP_NODELAY' /usr/include).

    – Chaos

    1. Februar 2010 um 17:20 Uhr

  • Nagle hätte eine wunderbare Sache sein können, wenn es einen TCP-Flush gegeben hätte. Da es seine Puffergröße auf die aktuelle Segmentgröße optimieren kann. Wenn Sie Nagle deaktivieren, haben Sie einen eigenen Puffer, der nicht auf die Segmentgröße synchronisiert ist, und senden daher halb gefüllte Pakete über das Netzwerk …

    – mmmmmmmm

    18. November 2010 um 9:13 Uhr


  • fflush hat nichts mit dem Problem zu tun, auch nicht für Unix-Domain-Sockets. Es ist nur relevant, wenn Sie Ihren Socket mit a umschlossen haben FILE über fdopen

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

    18. November 2011 um 3:41 Uhr

  • Was ich tue, ist, Nagle zu aktivieren, so viele Bytes (mit nicht blockierender E / A) wie möglich in den Socket zu schreiben (dh bis mir die Bytes zum Senden ausgehen oder der Aufruf von send () EWOULDBLOCK zurückgibt, je nachdem, was zuerst eintritt). , und deaktivieren Sie dann Nagle erneut. Dies scheint gut zu funktionieren (d. h. ich bekomme wo möglich eine geringe Latenz UND Pakete in voller Größe)

    – Jeremy Friesner

    25. April 2013 um 14:46 Uhr


hagellos Benutzeravatar
hagello

In RFC 1122 lautet der Name der Sache, nach der Sie suchen, “PUSH”. Es scheint jedoch keine relevante TCP-API-Implementierung zu geben, die “PUSH” implementiert. Leider kein Glück.

Einige Antworten und Kommentare befassen sich mit dem Nagle-Algorithmus. Die meisten von ihnen scheinen davon auszugehen, dass der Nagle-Algorithmus jedes Mal verzögert jeder senden. Diese Annahme ist nicht richtig. Nagle verzögert das Senden nur wenn mindestens eines der vorherigen Pakete noch nicht bestätigt wurde (http://www.unixguide.net/network/socketfaq/2.11.shtml).

Anders ausgedrückt: TCP sendet die Erste Paket (einer Reihe von Paketen) sofort. Nur wenn die Verbindung langsam ist und Ihr Computer keine rechtzeitige Bestätigung erhält, verzögert Nagle das Senden nachfolgende Daten bis entweder (was zuerst eintritt)

  • eine Auszeit erreicht ist oder
  • das letzte unbestätigte Paket wird bestätigt oder
  • Ihr Sendepuffer ist voll oder
  • Sie deaktivieren Nagle oder
  • Sie schalten die Senderichtung Ihrer Verbindung ab

Eine gute Milderung ist es, das Geschäft zu vermeiden nachfolgende Daten so weit wie möglich. Das bedeutet: Ruft Ihre Anwendung auf send() mehr als einmal, um eine einzelne zusammengesetzte Anfrage zu übermitteln, versuchen Sie, Ihre Anwendung neu zu schreiben. Stellen Sie die zusammengesetzte Anfrage im Benutzerbereich zusammen und rufen Sie sie dann auf send(). Einmal. Dies spart auch Kontextwechsel (viel teurer als die meisten User-Space-Operationen).

Außerdem, wenn der Sendepuffer genug Daten enthält, um die maximale Größe eines Netzwerkpakets zu füllen, verzögert Nagle auch nicht. Das bedeutet: Wenn das letzte Paket, das Sie senden, groß genug ist, um Ihren Sendepuffer zu füllen, sendet TCP Ihre Daten so schnell wie möglich, egal was passiert.

Um es zusammenzufassen: Nagle ist nicht der Brute-Force-Ansatz zur Reduzierung der Paketfragmentierung, für den manche ihn halten könnten. Im Gegenteil: Mir scheint es ein sinnvoller, dynamischer und effektiver Ansatz zu sein, sowohl eine gute Antwortzeit als auch ein gutes Verhältnis zwischen Nutzdaten und Kopfdaten einzuhalten. Davon abgesehen sollten Sie wissen, wie Sie effizient damit umgehen.

Benutzeravatar von Tall Jeff
Der große Jeff

Mir ist in der Standard-TCP/IP-Socket-Schnittstelle keine Möglichkeit bekannt, die Daten “vollständig bis zum entfernten Ende” zu spülen und sicherzustellen, dass sie tatsächlich bestätigt wurden.

Wenn Ihr Protokoll eine Datenübertragung in “Echtzeit” erfordert, ist es im Allgemeinen am besten, das einzustellen setsockopt() von TCP_NODELAY. Dadurch wird der Nagle-Algorithmus im Protokollstapel deaktiviert und write() oder send() auf dem Socket werden direkter auf das Senden an das Netzwerk abgebildet … anstatt Sende-Hold-Offs zu implementieren und darauf zu warten, dass mehr Bytes verfügbar werden, und alle zu verwenden Timer auf TCP-Ebene, um zu entscheiden, wann gesendet werden soll. ANMERKUNG: Das Deaktivieren von Nagle deaktiviert nicht das TCP-Schiebefenster oder ähnliches, also ist es immer sicher, dies zu tun …. aber wenn Sie die “Echtzeit”-Eigenschaften nicht benötigen, kann der Paket-Overhead ziemlich hoch werden.

Wenn darüber hinaus die normalen TCP-Socket-Mechanismen nicht zu Ihrer Anwendung passen, müssen Sie im Allgemeinen auf die Verwendung von UDP zurückgreifen und Ihre eigenen Protokollfunktionen auf den grundlegenden Sende-/Empfangseigenschaften von UDP aufbauen. Dies ist sehr häufig, wenn Ihr Protokoll spezielle Anforderungen hat, aber unterschätzen Sie nicht die Komplexität, dies gut zu machen und es in allen außer relativ einfachen Anwendungen stabil und funktional korrekt zu machen. Als Ausgangspunkt wird eine gründliche Untersuchung der Designmerkmale von TCP Licht auf viele der zu berücksichtigenden Probleme werfen.

Ich denke, es wäre extrem schwierig, wenn nicht unmöglich, es richtig umzusetzen. Was bedeutet „bündig“ in diesem Zusammenhang? Bytes an Netzwerk übertragen? Vom TCP-Stack des Empfängers bestätigte Bytes? An die Benutzermodus-App des Empfängers übergebene Bytes? Bytes vollständig von Benutzermodus-App verarbeitet?

Sieht so aus, als müssten Sie es auf App-Ebene tun …

  • Nagle = nicht sofort an Wire senden. Kein Nagle = sofort an Wire senden. Die Zwischenoption starrt jedem direkt ins Gesicht: nicht sofort an Wire senden (Nagle), außer wenn ich „Jetzt senden“ sage (der schwer fassbare TCP-Flush).

    – Roman Starkow

    17. Juli 2011 um 21:02 Uhr

  • @romkyns Trotzdem ist das eigentliche send() asynchron zum Senden, unabhängig vom Nagle-Status.

    – Benutzer207421

    18. Juli 2014 um 20:34 Uhr

  • @ Roman Nagle tut es nicht unbedingt gleich nicht sofort an Wire senden.

    – Hagello

    3. Mai um 19:46 Uhr


Benutzeravatar von Norman Ramsey
Norman Ramsey

TCP bietet nur die bestmögliche Zustellung, sodass das Verlassen aller Bytes von Maschine A asynchron mit dem Empfang aller Bytes auf Maschine B erfolgt. Der TCP/IP-Protokollstapel weiß es natürlich, aber ich kenne keinen Möglichkeit, den TCP-Stack abzufragen, um herauszufinden, ob alles, was gesendet wurde, bestätigt wurde.

Der bei weitem einfachste Weg, die Frage zu beantworten, ist auf Anwendungsebene. Öffnen Sie einen zweiten TCP-Socket, um als Rückkanal zu fungieren, und lassen Sie sich vom Remote-Partner bestätigen, dass er die gewünschten Informationen erhalten hat. Es kostet das Doppelte, ist aber vollständig portabel und spart Ihnen Stunden Programmierzeit.

  • Nagle = nicht sofort an Wire senden. Kein Nagle = sofort an Wire senden. Die Zwischenoption starrt jedem direkt ins Gesicht: nicht sofort an Wire senden (Nagle), außer wenn ich „Jetzt senden“ sage (der schwer fassbare TCP-Flush).

    – Roman Starkow

    17. Juli 2011 um 21:02 Uhr

  • @romkyns Trotzdem ist das eigentliche send() asynchron zum Senden, unabhängig vom Nagle-Status.

    – Benutzer207421

    18. Juli 2014 um 20:34 Uhr

  • @ Roman Nagle tut es nicht unbedingt gleich nicht sofort an Wire senden.

    – Hagello

    3. Mai um 19:46 Uhr


Benutzeravatar von user1402866
Benutzer1402866

Sie können die tcp-Option SO_LINGER so einstellen, dass ein bestimmtes Timeout festgelegt wird, und dann den Socket schließen, um sicherzustellen, dass alle Daten gesendet wurden (oder Fehler beim Schließen einer Verbindung erkennen). Abgesehen davon ist TCP ein “Best Effort”-Protokoll und bietet keine wirklichen Garantien dafür, dass Daten jemals tatsächlich das Ziel erreichen (im Gegensatz zu dem, was manche zu glauben scheinen), es versucht nur, es so gut wie möglich zuzustellen in der richtigen Reihenfolge und so schnell wie möglich.

1408350cookie-checkGibt es eine Möglichkeit, einen POSIX-Socket zu leeren?

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

Privacy policy