在同一套接字上发送/接收的并行调用是否有效?


127
  1. 我们可以在同一个套接字上从一个线程调用send并从另一个线程调用recv吗?
  2. 我们可以在同一套接字上从不同线程调用多个并行发送吗?

我知道好的设计应该避免这种情况,但是我不清楚这些系统API的行为方式。同样,我也找不到很好的文档。

方向上的任何指针都会有所帮助。


3
您为何声称这样做是不良做法?对我来说,这很好,因为您在不同的线程中进行收听和接收。
TheMathNoob

Answers:


92

POSIX将send / recv定义为原子操作,因此假设您在谈论POSIX send / recv,那么可以,您可以从多个线程同时调用它们,然后一切正常。

这不一定意味着它们将并行执行-在多次发送的情况下,第二个可能会阻塞直到第一个完成。您可能不会注意到太多,因为发送一旦将其数据放入套接字缓冲区就完成了。

如果您使用的是SOCK_STREAM套接字,则尝试并行执行操作的可能性较小,因为send / recv可能仅发送或接收部分消息,这意味着事情可能会分开。

在SOCK_STREAM套接字上阻塞发送/接收仅阻塞,直到它们发送或接收至少1个字节为止,因此阻塞与非阻塞之间的区别没有用。


1
@Joao:SOCK_DGRAM套接字被记录为“保留消息边界”,这不是很清楚。通过查看linux内核源,您至少可以看到每个send和recv原子地处理单个数据包(至少对于udp)。
克里斯·多德

2
@Kedar:不确定您的意思。send一旦将数据放入发送缓冲区,A就会返回,并且数据通过netowrk堆栈继续发送,并异步发送到网络上。因此,如果您有一个发送线程和一个接收线程,则发送线程在接收线程接收第一个数据包之前完全有可能(甚至可能)发送许多数据包。它完全异步,而不是同时发生。
克里斯·多德

6
@ChrisDodd,您可以为“ POSIX将send / recv定义为原子操作”提供链接吗?
Suitianshi '16

2
@suitianshi:POSIX 1003.1c标准文档列出了1003.1中所有可重入(可以从线程安全调用)而不能重入的功能。不幸的是,我不知道可以在任何地方获得免费的在线副本。
克里斯·多德

2
@ChrisDodd我在unix-systems.org/version4上找到了副本,我可以在7.1章看到系统接口表的列表,但看不到它在哪里将这些功能列为原子操作。不用怀疑,但是您可以分享/编辑您的答案以证明您在文档中的观点正确吗?
user153882'7

17

套接字描述符属于进程,而不属于特定线程。因此,可以在不同线程中向同一套接字发送/从同一套接字接收消息,操作系统将处理同步。

但是,如果发送/接收的顺序在语义上很重要,那么您自己(分别是您的代码)就必须确保不同线程中的操作之间正确排序(与线程一样)。


4

我看不到并行接收如何完成任何工作。如果有3个字节的消息,则1个线程可以得到第一个2个字节,而另一个则得到最后一个字节,但是您无法知道哪个是哪个。除非您的消息只有一个字节长,否则无法可靠地使多个线程接收任何内容。

如果您在一次通话中发送了整个邮件,则多次发送可能会起作用,但是我不确定。一个人可能会覆盖另一个人。这样做绝对不会对性能产生任何好处。

如果需要发送多个线程,则应实现一个同步的消息队列。具有一个实际执行发送操作的线程,该线程从队列中读取消息,而让其他线程使整个消息入队。相同的东西对于接收也适用,但是接收线程将必须知道消息的格式,以便可以正确地反序列化它们。


9
如果您使用的是SOCK_DGRAM套接字,则每个recv将获得一个数据报。它永远不会在收看电视节目之间分裂
克里斯·多德

2
@noah,我同意并行recvs无法完成任何操作。这就是为什么我没有问过。我的问题是发送/接收并行,然后多个发送并行。您的回答确实可以洞悉并行发送。谢谢你。
杰伊,

1
@克里斯好点。我假设使用TCP。@Jay您可能想澄清一个问题:“我们可以叫发送/接收并行”听起来像您想并行接收吗?
诺亚2009年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.