As chamadas paralelas para enviar / receber no mesmo soquete são válidas?

127
  1. Podemos chamar send de um thread e recv de outro no mesmo socket?
  2. Podemos chamar vários envios paralelamente de diferentes threads no mesmo soquete?

Sei que um bom design deve evitar isso, mas não estou claro como essas APIs de sistema se comportarão. Não consigo encontrar uma boa documentação também para o mesmo.

Qualquer ponteiro na direção será útil.

Jay
fonte
3
por que você afirma que isso é uma má prática? Parece bom para mim, porque você ouve e recebe em diferentes tópicos.
TheMathNoob 2/17/17

Respostas:

92

O POSIX define send / recv como operações atômicas, portanto, supondo que você esteja falando sobre o POSIX send / recv, sim, você pode chamá-los simultaneamente a partir de vários threads e tudo funcionará.

Isso não significa necessariamente que eles serão executados em paralelo - no caso de envios múltiplos, o segundo provavelmente bloqueará até que o primeiro seja concluído. Você provavelmente não notará muito, pois o envio é concluído quando os dados são colocados no buffer do soquete.

Se você estiver usando soquetes SOCK_STREAM, é menos provável que tentar fazer coisas em paralelo seja útil, pois enviar / receber pode enviar ou receber apenas parte de uma mensagem, o que significa que as coisas podem ser divididas.

O bloqueio de envio / recv nos soquetes SOCK_STREAM apenas bloqueia até que eles enviem ou recebam novamente pelo menos 1 byte, portanto, a diferença entre bloqueio e não bloqueio não é útil.

Chris Dodd
fonte
1
@ João: o soquete SOCK_DGRAM está documentado como "preservando os limites da mensagem", o que não é muito claro. Observando as fontes do kernel do Linux, você pode pelo menos ver que cada envio e recv lida com um único pacote atomicamente (pelo menos para o udp).
Chris Dodd
2
@ Kedar: não sei o que você quer dizer. Um sendretorna assim que os dados são colocados no buffer de envio e os dados são enviados através da pilha netowrk e enviados para a rede de forma assíncrona. Portanto, se você tiver um envio de thread e um recebimento de thread, é perfeitamente possível (até provável) que o thread de envio envie muitos pacotes antes que o thread de recebimento receba o primeiro pacote. É totalmente assíncrono e não simultâneo.
precisa saber é o seguinte
6
@ ChrisDodd, você pode fornecer um link para "POSIX define send / recv como operações atômicas"?
suitianshi
2
@suitianshi: O documento padrão POSIX 1003.1c lista todas as funções no 1003.1 que são reentrantes (seguras para chamar de threads) e que não são. Infelizmente, não conheço uma cópia on-line gratuita disponível em qualquer lugar.
21816 Chris Dodd
2
@ChrisDodd Encontrei a cópia em unix-systems.org/version4 e posso ver a lista da Tabela de Interface do Sistema no capítulo 7.1, mas não vejo onde ela lista as funções como operações atômicas. Para não duvidar de você, mas você pode compartilhar / editar sua resposta para justificar seu ponto no documento?
user153882
17

O descritor de soquete pertence ao processo, não a um encadeamento específico. Portanto, é possível enviar / receber para / do mesmo soquete em diferentes threads, o sistema operacional manipulará a sincronização.

No entanto, se a ordem de envio / recebimento for semanticamente significativa, você mesmo (respectivamente seu código) precisará garantir o seqüenciamento adequado entre as operações nos diferentes threads - como sempre acontece com os threads.

Adrian Willenbücher
fonte
4

Não vejo como receber em paralelo poderia realizar alguma coisa. Se você tiver uma mensagem de 3 bytes, 1 thread poderá obter o primeiro 2 bytes e outro o último byte, mas você não terá como saber qual é qual. A menos que suas mensagens tenham apenas um byte, não há como você fazer com que algo funcione de maneira confiável com o recebimento de vários threads.

Vários envios podem funcionar, se você enviou a mensagem inteira em uma única chamada, mas não tenho certeza. É possível que um possa substituir outro. Certamente não haveria nenhum benefício de desempenho em fazê-lo.

Se for necessário enviar vários encadeamentos, você deve implementar uma fila de mensagens sincronizadas. Tem um thread que faz o envio real que lê mensagens da fila e os outros threads enfileiram mensagens inteiras. O mesmo funcionaria para receber, mas o encadeamento de recebimento precisaria saber o formato das mensagens para poder desserializá-las adequadamente.

Noé
fonte
9
Se você estiver usando soquetes SOCK_DGRAM, cada recv obterá um único datagrama; ele nunca vai ser dividido entre recvs
Chris Dodd
2
@ noah, eu concordo recvs paralelo não pode realizar nada. Por isso não perguntei. Minha pergunta é enviar / recuperar paralelamente e, em seguida, vários envios paralelos. Sua resposta fornece uma visão dos envios paralelos. Obrigado pelo mesmo.
314 Jay
1
@ Chris bom ponto. Eu estava assumindo o TCP. @ Jay Você pode esclarecer a pergunta "Podemos ligar para enviar / receber em paralelo" parece que você deseja receber em paralelo.
Noah