Was ist der Unterschied zwischen read () und recv () und zwischen send () und write ()?
198
Was ist der Unterschied zwischen read()und recv()und zwischen send()und write()in der Socket-Programmierung in Bezug auf Leistung, Geschwindigkeit und andere Verhaltensweisen?
Stellen Sie sich das Schreiben so vor : #define write(...) send(##__VA_ARGS__, 0).
carefulnow1
Antworten:
128
Der Unterschied besteht darin, dass recv()/ send()nur an Socket-Deskriptoren arbeitet und Sie bestimmte Optionen für die eigentliche Operation angeben können. Diese Funktionen sind etwas spezialisierter (Sie können beispielsweise ein Flag zum Ignorieren setzenSIGPIPE oder zum Senden von Out-of-Band-Nachrichten setzen ...).
Funktionen read()/ write()sind die universellen Dateideskriptorfunktionen, die an allen Deskriptoren arbeiten.
Dies ist falsch, es gibt einen weiteren Unterschied bei Datagrammen mit einer Länge von 0 - Wenn ein Datagramm mit einer Länge von Null ansteht, bieten read (2) und recv () mit einem Flags-Argument von Null ein anderes Verhalten. Unter diesen Umständen hat read (2) keine Auswirkung (das Datagramm steht noch aus), während recv () das anstehende Datagramm verwendet.
Abhinav Gauniyal
2
@AbhinavGauniyal Wie würde das ein anderes Verhalten bewirken ? Wenn es eine 0 - Byte - Datagramm ist, beide, recvund es readwerden keine Daten an den Aufrufer liefern , sondern auch kein Fehler. Für den Anrufer ist das Verhalten dasselbe. Der Anrufer weiß möglicherweise nicht einmal etwas über Datagramme (er weiß möglicherweise nicht, dass dies ein Socket und keine Datei ist, er weiß möglicherweise nicht, dass dies ein Datagramm-Socket und kein Stream-Socket ist). Dass das Datagramm aussteht, ist implizites Wissen darüber, wie IP-Stacks in Kerneln funktionieren und für den Aufrufer nicht sichtbar sind. Aus Sicht des Anrufers bieten sie weiterhin das gleiche Verhalten.
Mecki
2
@Mecki, das ist nicht implizites Wissen für alle, nehmen Sie mich zum Beispiel :)
Abhinav Gauniyal
1
@Mecki Was bedeutet ein nicht blockierendes erfolgreiches Lesen von 0 Bytes? Bleibt das Datagramm noch ausstehend? Genau das und nur das beunruhigt mich: das Verhalten, dass ein Datagramm auch bei erfolgreichem Lesen anstehend bleiben kann. Ich bin mir nicht sicher, ob die Situation eintreten kann, weshalb ich sie gerne im Auge behalten würde.
sehe
2
@sehe Wenn Sie sich Sorgen machen, warum verwenden Sie nicht recv? Der Grund, warum recvund sendwo überhaupt eingeführt wurde, war die Tatsache, dass nicht alle Datagrammkonzepte auf die Welt der Streams abgebildet werden konnten. readund writebehandeln Sie alles als einen Datenstrom, sei es eine Pipe, eine Datei, ein Gerät (z. B. eine serielle Schnittstelle) oder ein Socket. Ein Socket ist jedoch nur dann ein echter Stream, wenn er TCP verwendet. Wenn es UDP verwendet, ist es eher ein Blockgerät. Wenn beide Seiten es jedoch wie einen Stream verwenden, funktioniert es wie ein Stream, und Sie können nicht einmal ein leeres UDP-Paket mithilfe von writeAufrufen senden , sodass diese Situation nicht auftritt.
read () entspricht recv () mit einem Flags-Parameter von 0. Andere Werte für den Flags-Parameter ändern das Verhalten von recv (). In ähnlicher Weise entspricht write () send () mit Flags == 0.
Das ist nicht die ganze Geschichte. recvkann nur für einen Socket verwendet werden und erzeugt einen Fehler, wenn Sie versuchen, ihn beispielsweise für einen Socket zu verwenden STDIN_FILENO.
Joey Adams
76
Dieser Thread ist jetzt der erste Treffer bei Google, Google liebt Stackoverflow
Eloff
12
read()und write()sind allgemeiner, sie arbeiten mit jedem Dateideskriptor. Unter Windows funktionieren sie jedoch nicht.
Sie können zusätzliche Optionen an send()und übergeben recv(), sodass Sie sie in einigen Fällen möglicherweise verwenden müssen.
Ich habe erst kürzlich bemerkt, dass write()es fast funktioniert , wenn ich einen Socket in Windows verwendet habe (der FD, an den übergeben wurde, write()ist nicht der gleiche wie der, an den übergeben wurde send(); ich habe _open_osfhandle()den FD dazu gebracht, an zu übergeben write()). Es hat jedoch nicht funktioniert, als ich versucht habe, Binärdaten zu senden, die Zeichen 10 enthielten. write()Irgendwo zuvor wurde Zeichen 13 eingefügt. Das Ändern send()mit einem Flags-Parameter von 0 hat dieses Problem behoben. read()könnte das umgekehrte Problem haben, wenn 13-10 in den Binärdaten aufeinanderfolgend sind, aber ich habe es nicht getestet. Aber das scheint ein weiterer möglicher Unterschied zwischen send()und zu sein write().
"Leistung und Geschwindigkeit"? Sind das nicht ... Synonyme hier?
Auf jeden Fall recv()nimmt der Anruf Flags entgegen, die read()dies nicht tun, was ihn leistungsfähiger oder zumindest bequemer macht. Das ist ein Unterschied. Ich glaube nicht, dass es einen signifikanten Leistungsunterschied gibt, habe ihn aber nicht getestet.
Vielleicht wird es als bequemer empfunden, sich nicht mit Flaggen befassen zu müssen.
Semaj
2
Unter Linux stelle ich außerdem fest, dass:
Unterbrechung von Systemaufrufen und Bibliotheksfunktionen durch Signalhandler
Wenn ein Signalhandler aufgerufen wird, während ein Systemaufruf oder ein Bibliotheksfunktionsaufruf blockiert ist, gilt Folgendes:
Der Anruf wird automatisch neu gestartet, nachdem der Signalhandler zurückgekehrt ist. oder
Der Aufruf schlägt mit dem Fehler EINTR fehl.
... Die Details variieren zwischen UNIX-Systemen. unten die Details für Linux.
Wenn ein blockierter Anruf an eine der folgenden Schnittstellen von einem Signalhandler unterbrochen wird, wird der Anruf automatisch neu gestartet, nachdem der Signalhandler zurückgekehrt ist, wenn das Flag SA_RESTART verwendet wurde. Andernfalls schlägt der Aufruf mit dem Fehler EINTR fehl:
read (2), readv (2), write (2), writev (2) und ioctl (2) rufen auf "langsamen" Geräten auf.
..... .....
Die folgenden Schnittstellen werden unabhängig von der Verwendung von SA_RESTART niemals neu gestartet, nachdem sie von einem Signalhandler unterbrochen wurden. Sie schlagen immer mit dem Fehler EINTR fehl, wenn sie von einem Signalhandler unterbrochen werden:
Socket-Schnittstellen "Eingabe", wenn für das Socket mit setsockopt (2) ein Timeout (SO_RCVTIMEO) festgelegt wurde: accept (2), recv (2),
recvfrom (2), recvmmsg (2) (auch mit einem Nicht-NULL-Wert) Timeout-Argument) und recvmsg (2).
"Output" -Socket-Schnittstellen, wenn mit setsockopt (2) ein Timeout (SO_RCVTIMEO) für den Socket festgelegt wurde: connect (2), send (2), sendto (2) und sendmsg (2).
Überprüfen Sie man 7 signalfür weitere Details.
Eine einfache Verwendung wäre die Verwendung eines Signals, um ein recvfromunbegrenztes Blockieren zu vermeiden .
#define write(...) send(##__VA_ARGS__, 0)
.Antworten:
Der Unterschied besteht darin, dass
recv()
/send()
nur an Socket-Deskriptoren arbeitet und Sie bestimmte Optionen für die eigentliche Operation angeben können. Diese Funktionen sind etwas spezialisierter (Sie können beispielsweise ein Flag zum Ignorieren setzenSIGPIPE
oder zum Senden von Out-of-Band-Nachrichten setzen ...).Funktionen
read()
/write()
sind die universellen Dateideskriptorfunktionen, die an allen Deskriptoren arbeiten.quelle
recv
und esread
werden keine Daten an den Aufrufer liefern , sondern auch kein Fehler. Für den Anrufer ist das Verhalten dasselbe. Der Anrufer weiß möglicherweise nicht einmal etwas über Datagramme (er weiß möglicherweise nicht, dass dies ein Socket und keine Datei ist, er weiß möglicherweise nicht, dass dies ein Datagramm-Socket und kein Stream-Socket ist). Dass das Datagramm aussteht, ist implizites Wissen darüber, wie IP-Stacks in Kerneln funktionieren und für den Aufrufer nicht sichtbar sind. Aus Sicht des Anrufers bieten sie weiterhin das gleiche Verhalten.recv
? Der Grund, warumrecv
undsend
wo überhaupt eingeführt wurde, war die Tatsache, dass nicht alle Datagrammkonzepte auf die Welt der Streams abgebildet werden konnten.read
undwrite
behandeln Sie alles als einen Datenstrom, sei es eine Pipe, eine Datei, ein Gerät (z. B. eine serielle Schnittstelle) oder ein Socket. Ein Socket ist jedoch nur dann ein echter Stream, wenn er TCP verwendet. Wenn es UDP verwendet, ist es eher ein Blockgerät. Wenn beide Seiten es jedoch wie einen Stream verwenden, funktioniert es wie ein Stream, und Sie können nicht einmal ein leeres UDP-Paket mithilfe vonwrite
Aufrufen senden , sodass diese Situation nicht auftritt.Nach dem ersten Treffer bei Google
quelle
recv
kann nur für einen Socket verwendet werden und erzeugt einen Fehler, wenn Sie versuchen, ihn beispielsweise für einen Socket zu verwendenSTDIN_FILENO
.read()
undwrite()
sind allgemeiner, sie arbeiten mit jedem Dateideskriptor. Unter Windows funktionieren sie jedoch nicht.Sie können zusätzliche Optionen an
send()
und übergebenrecv()
, sodass Sie sie in einigen Fällen möglicherweise verwenden müssen.quelle
Ich habe erst kürzlich bemerkt, dass
write()
es fast funktioniert , wenn ich einen Socket in Windows verwendet habe (der FD, an den übergeben wurde,write()
ist nicht der gleiche wie der, an den übergeben wurdesend()
; ich habe_open_osfhandle()
den FD dazu gebracht, an zu übergebenwrite()
). Es hat jedoch nicht funktioniert, als ich versucht habe, Binärdaten zu senden, die Zeichen 10 enthielten.write()
Irgendwo zuvor wurde Zeichen 13 eingefügt. Das Ändernsend()
mit einem Flags-Parameter von 0 hat dieses Problem behoben.read()
könnte das umgekehrte Problem haben, wenn 13-10 in den Binärdaten aufeinanderfolgend sind, aber ich habe es nicht getestet. Aber das scheint ein weiterer möglicher Unterschied zwischensend()
und zu seinwrite()
.quelle
Eine andere Sache unter Linux ist:
send
erlaubt nicht, auf Nicht-Socket-FD zu arbeiten. So ist beispielsweise das Schreiben auf den USB-Portwrite
erforderlich.quelle
"Leistung und Geschwindigkeit"? Sind das nicht ... Synonyme hier?
Auf jeden Fall
recv()
nimmt der Anruf Flags entgegen, dieread()
dies nicht tun, was ihn leistungsfähiger oder zumindest bequemer macht. Das ist ein Unterschied. Ich glaube nicht, dass es einen signifikanten Leistungsunterschied gibt, habe ihn aber nicht getestet.quelle
Unter Linux stelle ich außerdem fest, dass:
Überprüfen Sie
man 7 signal
für weitere Details.Eine einfache Verwendung wäre die Verwendung eines Signals, um ein
recvfrom
unbegrenztes Blockieren zu vermeiden .Ein Beispiel aus APUE :
quelle