Les appels parallèles pour envoyer / recevoir sur le même socket sont-ils valides?

127
  1. Pouvons-nous appeler send d'un thread et recv d'un autre sur le même socket?
  2. Pouvons-nous appeler plusieurs envois en parallèle à partir de différents threads sur le même socket?

Je sais qu'une bonne conception devrait éviter cela, mais je ne sais pas comment ces API système se comporteront. Je suis incapable de trouver une bonne documentation également pour le même.

Tout pointeur dans la direction sera utile.

Geai
la source
3
pourquoi prétendez-vous que cela est une mauvaise pratique ?. Cela me semble bien parce que vous écoutez et recevez de différents fils.
TheMathNoob

Réponses:

92

POSIX définit send / recv comme des opérations atomiques, donc en supposant que vous parlez d'envoi / recv POSIX alors oui, vous pouvez les appeler simultanément à partir de plusieurs threads et les choses fonctionneront.

Cela ne signifie pas nécessairement qu'ils seront exécutés en parallèle - dans le cas d'envois multiples, le second bloquera probablement jusqu'à ce que le premier se termine. Vous ne le remarquerez probablement pas beaucoup, car un envoi se termine une fois qu'il a mis ses données dans le tampon de socket.

Si vous utilisez des sockets SOCK_STREAM, essayer de faire des choses en parallèle est moins susceptible d'être utile car send / recv peut envoyer ou recevoir seulement une partie d'un message, ce qui signifie que les choses pourraient se diviser.

Le blocage d'envoi / réception sur les sockets SOCK_STREAM ne bloque que jusqu'à ce qu'ils envoient ou reçoivent au moins 1 octet, donc la différence entre bloquant et non bloquant n'est pas utile.

Chris Dodd
la source
1
@Joao: Les sockets SOCK_DGRAM sont documentés comme «préservant les limites des messages», ce qui n'est pas très clair. En regardant les sources du noyau Linux, vous pouvez au moins voir que chaque envoi et chaque réception traite un seul paquet de manière atomique (au moins pour udp).
Chris Dodd
2
@Kedar: je ne sais pas ce que tu veux dire. Un sendretourne dès que les données sont placées dans le tampon d'envoi, et les données sont envoyées via la pile netowrk et sur le réseau de manière asynchrone. Donc, si vous avez un thread d'envoi et un thread de réception, il est tout à fait possible (même probable) pour le thread d'envoi d'envoyer plusieurs paquets avant que le thread de réception ne reçoive le premier paquet. C'est entièrement asynchrone et non simultané.
Chris Dodd
6
@ChrisDodd, pouvez-vous donner un lien pour "POSIX définit send / recv comme des opérations atomiques"?
suitianshi
2
@suitianshi: Le document standard POSIX 1003.1c répertorie toutes les fonctions de 1003.1 qui sont réentrantes (appelables à partir de threads) et qui ne le sont pas. Je ne suis malheureusement pas au courant d'une copie en ligne gratuite disponible nulle part.
Chris Dodd
2
@ChrisDodd J'ai trouvé la copie sur unix-systems.org/version4 et je peux voir la liste de System Interface Table au chapitre 7.1 mais je ne vois pas où il répertorie les fonctions comme étant des opérations atomiques. Ne pas douter de vous, mais pouvez-vous s'il vous plaît partager / modifier votre réponse pour justifier votre point dans le document?
user153882
17

Le descripteur de socket appartient au processus, pas à un thread particulier. Par conséquent, il est possible d'envoyer / recevoir vers / depuis le même socket dans différents threads, le système d'exploitation gérera la synchronisation.

Cependant, si l'ordre d'envoi / réception est sémantiquement significatif, vous-même (respectivement votre code) devez vous assurer d'un bon séquencement entre les opérations dans les différents threads - comme c'est toujours le cas avec les threads.

Adrian Willenbücher
la source
4

Je ne vois pas comment recevoir en parallèle pourrait accomplir quoi que ce soit. Si vous avez un message de 3 octets, 1 thread pourrait obtenir les 2 premiers octets et un autre le dernier octet, mais vous n'auriez aucun moyen de dire lequel était lequel. À moins que vos messages ne durent qu'un octet, il n'y a aucun moyen de faire fonctionner quoi que ce soit de manière fiable avec la réception de plusieurs threads.

Plusieurs envois peuvent fonctionner, si vous avez envoyé l'intégralité du message en un seul appel, mais je ne suis pas sûr. Il est possible que l'un puisse en écraser un autre. Il n'y aurait certainement aucun avantage en termes de performances à le faire.

Si plusieurs threads doivent être envoyés, vous devez implémenter une file d'attente de messages synchronisés. Avoir un thread qui effectue l'envoi réel qui lit les messages de la file d'attente et que les autres threads mettent des messages entiers en file d'attente. La même chose fonctionnerait pour la réception, mais le thread de réception devrait connaître le format des messages afin de pouvoir les désérialiser correctement.

Noé
la source
9
Si vous utilisez des sockets SOCK_DGRAM, chaque recv obtiendra un seul datagramme; il ne sera jamais divisé entre les recvs
Chris Dodd
2
@noah, je suis d'accord que les recvs parallèles ne peuvent rien accomplir. C'est pourquoi je ne l'ai pas demandé. Ma question est envoyer / recevoir en parallèle, puis plusieurs envois en parallèle. Votre réponse donne un aperçu des envois parallèles. Merci pour la même chose.
Jay
1
@Chris bon point. J'assumais TCP. @Jay Vous pourriez clarifier la question "Pouvons-nous appeler send / recv en parallèle" sonne comme vous voulez recevoir en parallèle.
noah