Sind parallele Anrufe zum Senden / Empfangen über denselben Socket gültig?

126
  1. Können wir send von einem Thread und recv von einem anderen auf demselben Socket aufrufen?
  2. Können wir mehrere Sends parallel von verschiedenen Threads am selben Socket aufrufen?

Ich weiß, dass ein gutes Design dies vermeiden sollte, aber mir ist nicht klar, wie sich diese System-APIs verhalten werden. Ich kann auch dafür keine gute Dokumentation finden.

Hinweise in die Richtung sind hilfreich.

Jay
quelle
2
Warum behaupten Sie, dass dies eine schlechte Praxis ist? Es sieht für mich gut aus, weil Sie in verschiedenen Threads zuhören und empfangen.
TheMathNoob

Antworten:

92

POSIX definiert send / recv als atomare Operationen. Wenn Sie also von POSIX send / recv sprechen, können Sie sie gleichzeitig von mehreren Threads aus aufrufen, und die Dinge funktionieren.

Dies bedeutet nicht unbedingt, dass sie parallel ausgeführt werden. Bei mehreren Sends wird der zweite wahrscheinlich blockiert, bis der erste abgeschlossen ist. Sie werden wahrscheinlich nicht so viel bemerken, da ein Sendevorgang abgeschlossen ist, sobald seine Daten in den Socket-Puffer gestellt wurden.

Wenn Sie SOCK_STREAM-Sockets verwenden, ist es weniger wahrscheinlich, dass Sie versuchen, Dinge parallel auszuführen, da send / recv möglicherweise nur einen Teil einer Nachricht sendet oder empfängt, was bedeutet, dass die Dinge aufgeteilt werden können.

Das Blockieren von send / recv auf SOCK_STREAM-Sockets wird nur blockiert, bis sie mindestens 1 Byte senden oder empfangen, sodass der Unterschied zwischen blockierend und nicht blockierend nicht sinnvoll ist.

Chris Dodd
quelle
1
@Joao: SOCK_DGRAM-Sockets werden als "Beibehalten von Nachrichtengrenzen" dokumentiert, was nicht sehr klar ist. Anhand der Linux-Kernel-Quellen können Sie zumindest erkennen, dass jedes Senden und Empfangen ein einzelnes Paket atomar behandelt (zumindest für udp).
Chris Dodd
2
@Kedar: Ich bin mir nicht sicher, was du meinst. A sendkehrt zurück, sobald die Daten in den Sendepuffer gestellt wurden, und die Daten werden asynchron über den Netzwerkstapel an das Netzwerk weitergeleitet. Wenn Sie also einen Thread senden und einen Thread empfangen, ist es durchaus möglich (sogar wahrscheinlich), dass der sendende Thread viele Pakete sendet, bevor der empfangende Thread das erste Paket empfängt. Es ist völlig asynchron und nicht gleichzeitig.
Chris Dodd
6
@ChrisDodd, können Sie einen Link für "POSIX definiert send / recv als atomare Operationen" angeben?
Suitianshi
2
@suitianshi: Das POSIX 1003.1c-Standarddokument listet alle Funktionen in 1003.1 auf, die wiedereintrittsfähig sind (sicher vom Thread aus aufgerufen werden können) und nicht. Leider ist mir nirgendwo eine kostenlose Online-Kopie bekannt.
Chris Dodd
2
@ChrisDodd Ich habe die Kopie auf unix-systems.org/version4 gefunden und kann die Liste der Systemschnittstellentabelle in Kapitel 7.1 sehen, sehe aber nicht, wo die Funktionen als atomare Operationen aufgeführt sind. Um nicht an Ihnen zu zweifeln, aber können Sie bitte Ihre Antwort teilen / bearbeiten, um Ihren Punkt im Dokument zu rechtfertigen?
user153882
17

Der Socket-Deskriptor gehört zum Prozess, nicht zu einem bestimmten Thread. Daher ist es möglich, in verschiedenen Threads an denselben Socket zu senden / von diesem zu empfangen. Das Betriebssystem übernimmt die Synchronisation.

Wenn jedoch die Reihenfolge des Sendens / Empfangens semantisch bedeutsam ist, müssen Sie selbst (bzw. Ihr Code) eine ordnungsgemäße Reihenfolge zwischen den Vorgängen in den verschiedenen Threads sicherstellen - wie dies bei Threads immer der Fall ist.

Adrian Willenbücher
quelle
4

Ich sehe nicht ein, wie paralleles Empfangen möglicherweise etwas bewirken könnte. Wenn Sie eine 3-Byte-Nachricht haben, könnte 1 Thread die ersten 2 Bytes und ein anderer das letzte Byte erhalten, aber Sie hätten keine Möglichkeit zu sagen, welches welches war. Wenn Ihre Nachrichten nicht nur ein Byte lang sind, können Sie auf keinen Fall zuverlässig dafür sorgen, dass mehrere Threads empfangen.

Mehrere Sends können funktionieren , wenn Sie die gesamte Nachricht in einem einzigen Anruf gesendet haben, aber ich bin mir nicht sicher. Es ist möglich, dass einer den anderen überschreibt. Dies würde sicherlich keinen Leistungsvorteil bringen.

Wenn mehrere Threads gesendet werden müssen, sollten Sie eine synchronisierte Nachrichtenwarteschlange implementieren. Lassen Sie einen Thread das eigentliche Senden durchführen, das Nachrichten aus der Warteschlange liest, und lassen Sie die anderen Threads ganze Nachrichten in die Warteschlange stellen. Dasselbe würde für den Empfang funktionieren, aber der Empfangsthread müsste das Format der Nachrichten kennen, damit er sie ordnungsgemäß deserialisieren kann.

Noah
quelle
9
Wenn Sie SOCK_DGRAM-Sockets verwenden, erhält jeder Recv ein einzelnes Datagramm. es wird nie zwischen recvs aufgeteilt
Chris Dodd
2
@noah, ich bin damit einverstanden, dass parallele Recvs nichts bewirken können. Deshalb habe ich es nicht gefragt. Meine Frage ist parallel senden / empfangen und dann mehrere gleichzeitig senden. Ihre Antwort gibt einen Einblick in parallele Sendungen. Danke für das gleiche.
Jay
1
@ Chris guter Punkt. Ich nahm TCP an. @ Jay Vielleicht klären Sie die Frage "Können wir send / recv parallel anrufen?" Klingt so, als ob Sie parallel empfangen möchten.
Noah