Warum wird angenommen, dass send möglicherweise mit weniger als den angeforderten Daten zurückkehrt, die auf einem blockierenden Socket übertragen werden?

Lesezeit: 3 Minuten

Die Standardmethode zum Senden von Daten über einen Stream-Socket bestand schon immer darin, send mit einem zu schreibenden Datenblock aufzurufen, den Rückgabewert zu überprüfen, um festzustellen, ob alle Daten gesendet wurden, und dann erneut send aufzurufen, bis die gesamte Nachricht akzeptiert wurde.

Dies ist beispielsweise ein einfaches Beispiel für ein allgemeines Schema:

int send_all(int sock, unsigned char *buffer, int len) {
  int nsent;

  while(len > 0) {
    nsent = send(sock, buffer, len, 0);
    if(nsent == -1) // error
      return -1;

    buffer += nsent;
    len -= nsent;
  }
  return 0; // ok, all data sent
}

Sogar die BSD-Manpage erwähnt das

…Wenn am Socket kein Platz für Nachrichten verfügbar ist, um die zu übertragende Nachricht aufzunehmen, dann send() normalerweise blockiert

Was darauf hinweist, dass wir davon ausgehen sollten, dass send möglicherweise zurückkehrt, ohne alle Daten zu senden. Nun finde ich das ziemlich kaputt, aber selbst W. Richard Stevens geht davon in seinem Standard-Nachschlagewerk etwa aus Netzwerkprogrammierungnicht in den Anfangskapiteln, aber die fortgeschritteneren Beispiele verwenden seine eigene Funktion writen (alle Daten schreiben), anstatt write aufzurufen.

Jetzt halte ich dies immer noch für mehr oder weniger kaputt, denn wenn send nicht in der Lage ist, alle Daten zu übertragen oder die Daten im zugrunde liegenden Puffer zu akzeptieren und der Socket blockiert, dann sollte send blockieren und zurückkehren, wenn die gesamte Sendeanforderung akzeptiert wurde .

Ich meine, im obigen Codebeispiel passiert, wenn send mit weniger gesendeten Daten zurückkehrt, dass es direkt mit einer neuen Anfrage erneut aufgerufen wird. Was hat sich seit dem letzten Aufruf geändert? Beim Maximum sind einige hundert CPU-Zyklen vergangen, sodass der Puffer noch voll ist. Wenn send jetzt die Daten akzeptiert, warum konnte es sie vorher nicht akzeptieren?

Andernfalls werden wir mit einer ineffizienten Schleife enden, in der wir versuchen, Daten an einen Socket zu senden, der keine Daten akzeptieren kann, und es weiter versuchen, oder?

Es scheint also, als ob die Problemumgehung, falls erforderlich, zu stark ineffizientem Code führt, und unter diesen Umständen sollten blockierende Sockets überhaupt vermieden werden und stattdessen nicht blockierende Sockets zusammen mit select verwendet werden.

  • Es wird nicht angenommen. Dies kann nur in einem Interrupt- oder Non-Blocking-Modus geschehen.

    – Benutzer207421

    17. Januar 2020 um 8:43 Uhr

Benutzer-Avatar
Nikolai Fetissov

Was in der obigen Beschreibung fehlt, ist, dass Systemaufrufe unter Unix möglicherweise durch Signale unterbrochen werden. Das ist genau der Grund für die Sperrung send(2) könnte eine kurze Zählung zurückgeben.

  • Würde das nicht zu EINTR führen? Oder wird EINTR nur stattfinden, wenn der Anruf unterbrochen wird, bevor Daten wie in beschrieben übertragen werden manpagez.com/man/2/send und wenn Daten gesendet wurden, wird EINTR nicht ausgegeben und stattdessen die Menge der gesendeten Daten zurückgegeben?

    – Ernelli

    11. April 2010 um 21:28 Uhr

  • EINTR wird nur zurückgegeben, wenn noch keine Daten übertragen wurden (und der Signalhandler nicht mit dem SA_RESTART-Flag installiert wurde).

    – mark4o

    12. April 2010 um 15:22 Uhr

  • Ist das wirklich der einzige Grund? Würde das bedeuten, dass, wenn ich keine Signal-Handler installiere, die Schleife um das Senden unnötig wäre? Das würde mir einiges vereinfachen. Leider scheint die Dokumentation zu diesem Thema ziemlich rar zu sein …

    – lxgr

    17. Januar 2012 um 18:49 Uhr


  • @lxgr: SO_SNDTIMEO und eventuell auch close()Wenn Sie den fd in einem anderen Thread verwenden, kann dies zu kurzen Schreibvorgängen führen. Außerdem können Bibliotheken von Drittanbietern seltsame Dinge mit Signalen tun.

    – ninjalj

    24. Februar 2014 um 13:27 Uhr

  • Ah! Ich habe mich gefragt, warum es blockieren würde und Ihren Wunsch nicht erfüllen. Wie oft treten Signale auf?

    – Pepijn

    10. April 2014 um 15:06 Uhr

1347070cookie-checkWarum wird angenommen, dass send möglicherweise mit weniger als den angeforderten Daten zurückkehrt, die auf einem blockierenden Socket übertragen werden?

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

Privacy policy