Warum ist es davon ausgegangen, dass senden können zurück, mit weniger als die angeforderten Daten übertragen, die auf einem blockierenden socket?
Die standard-Methode zum senden von Daten über einen stream-socket seit jeher zu rufen, senden, mit einem Stück von Daten zu schreiben, überprüfen Sie den Rückgabewert, um festzustellen, ob alle Daten gesendet wurden und dann halten Sie den Aufruf erneut senden, bis die gesamte Nachricht akzeptiert wurde.
Zum Beispiel dies ist ein einfaches Beispiel für eine gemeinsame Regelung:
int send_all(int sock, unsigned char *buffer, int len) { int nsent; while(len > 0) { nsent = send(sock, buffer, len, 0); wenn(nsent == -1) //Fehler return -1; Puffer += nsent; len -= nsent; } return 0; //ok, alle Daten, die gesendet werden }
Sogar die BSD-manpage erwähnt, dass
...Wenn keine Nachrichten Speicherplatz verfügbar ist auf dem sockel zu halten, wird die Nachricht übertragen werden soll, dann senden() normalerweise Blöcke...
Was bedeutet, dass wir davon ausgehen sollten, dass senden können zurück, ohne das senden aller Daten. Jetzt finde ich diese eher gebrochen, aber auch W. Richard Stevens meint dazu in seinem Standardwerk über Netzwerk-Programmierung, nicht am Anfang der Kapitel, aber die fortgeschrittenen Beispiele verwendet seine eigenen geschrieben (write all data) - Funktion anstelle des Aufrufs schreiben.
Nun halte ich diese immer noch mehr oder weniger kaputt, da, wenn der Versand nicht in der Lage ist die übertragung aller Daten, oder übernehmen Sie die Daten in der zugrunde liegenden Puffer und der socket blockiert, dann senden blockieren sollte und zurückkehren, wenn die ganze Anfrage senden akzeptiert wurde.
Ich meine, im code-Beispiel oben, was passieren wird, wenn Retouren senden Sie mit weniger Daten gesendet, ist, dass es aufgerufen wird, werden die Rechte wieder mit einem neuen Antrag. Was hat sich geändert seit dem letzten Aufruf? Bei max ein paar hundert CPU-Zyklen bestanden haben, damit der Puffer noch voll. Wenn Sie jetzt akzeptiert die Daten, warum konnte nicht Sie es akzeptieren, dass es vor?
Sonst werden wir Ende upp mit einer ineffizienten Schleife, wo wir versuchen, zum senden von Daten über ein socket kann Daten annehmen und weiter versuchen, oder anderes?
So scheint es, die Problemumgehung, wenn nötig, Ergebnisse in stark ineffizienten code und in einem solchen Fall blockieren von sockets sollte vermieden werden, überhaupt eine non-blocking sockets zusammen mit wählen sollte stattdessen verwendet werden.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die Sache, die fehlt in der obigen Beschreibung ist in der Unix system calls kann unterbrochen werden, mit Signalen. Das ist genau der Grund blockieren
send(2)
könnte wieder eine kurze Zählung.close()
ing der fd in einem anderen thread verursachen kann kurz schreibt. Auch 3rd-party-libs kann tun seltsame Dinge mit den Signalen.Im wesentlichen, das Verhalten nur zusätzliche Flexibilität.
Überlegen, was passiert, wenn die internen send-Puffer noch Platz für weitere 300 bytes, und Sie bitten
send()
zu senden, 800 bytes.Was dazu neigt zu geschehen, ist, dass es akzeptiert den ersten 300 bytes und legt Sie in die socket-buffer, dann gibt. Wenn Sie wirklich wollen, zu blockieren, bis alle 800 bytes gegangen, dann haben Sie gerade den re-call
send()
für die letzten 500 bytes, und es wird blockiert (da die sende-Puffer voll ist). Auf der anderen Seite, wenn Sie möchten, jetzt etwas anderes zu tun, und versuchen Sie die verbleibenden 500 bytes später, können Sie das auch tun.send()
soll, zu blockieren, bis es ausreichend Puffer Speicherplatz (oder eine außergewöhnliche Bedingung wie unterbrochen durch ein signal passiert), gemäß POSIX. Natürlich, minimale Netzwerk-stack-Implementierungen Verhalten (uIP, iwip, ...) unterscheiden kann.send
/write
blockieren.Es ist eine ziemlich grundlegende Anforderung für ein effizientes transport-Mechanismus beinhaltet, dass die Gerätetreiber. Der König der heap-TCP ist, sorgt es dafür, egal, was Sie werfen es, es tut sein bestes, um die Daten über den Draht. Es tut ganz gut, es hat einen 9 Neunen Lieferung garantieren. Es erfordert in der Regel ein Erd-Beben oder jemand stolperte über ein Netzkabel nicht liefern, die Sie Versprechen.
Was bedeutet, dass Sie nicht haben sorgen zu machen, dass, wenn Sie das schreiben von Daten in eine Steckdose, das es nicht geliefert werden. Was bedeutet, dass der kernel-Treiber kann die Freiheit nehmen, zu sagen: "ich habe Raum zu speichern, bringen Sie es auf!" und geben den Benutzer-Modus-Programm eine schnelle Rückkehr in wichtigere Dinge, wie halten die Benutzeroberfläche aktualisiert.
Gute Sache. Wenn aus irgendeinem Grund Ihre Lieferung zu garantieren, muss stärker sein als das, vielleicht 12 Neunen, dann sollten Sie nicht verwenden TCP. Es ist getan worden, "reliable UDP" googelt gut. Obwohl es dazu neigt, neu erfunden, um immer und immer wieder. Viel Glück!