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

Posted

技术标签:

【中文标题】在同一个套接字上对发送/接收的并行调用是不是有效?【英文标题】:Are parallel calls to send/recv on the same socket valid?在同一个套接字上对发送/接收的并行调用是否有效? 【发布时间】:2010-12-31 04:23:25 【问题描述】:
    我们能否在同一个套接字上从一个线程调用 send 并从另一个线程调用 recv? 我们可以从同一个套接字上的不同线程并行调用多个发送吗?

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

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

【问题讨论】:

您为什么声称这样做是一种不好的做法?对我来说看起来不错,因为您在不同的线程中收听和接收。 【参考方案1】:

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

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

如果您使用的是 SOCK_STREAM 套接字,则尝试并行执行操作不太可能有用,因为发送/接收可能仅发送或接收消息的一部分,这意味着事情可能会被拆分。

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

【讨论】:

@Joao:SOCK_DGRAM 套接字被记录为“保留消息边界”,这不是很清楚。通过查看 linux 内核源代码,您至少可以看到每个 send 和 recv 都以原子方式处理单个数据包(至少对于 udp 而言)。 @Kedar:不确定你的意思。数据一放入发送缓冲区,send 就返回,数据通过网络堆栈继续发送并异步发送到网络上。因此,如果您有一个线程发送和一个线程接收,则发送线程完全有可能(甚至可能)在接收线程接收到第一个数据包之前发送许多数据包。它完全是异步的,而不是同时的。 @ChrisDodd,你能给一个“POSIX 将发送/接收定义为原子操作”的链接吗? @suitianshi:POSIX 1003.1c 标准文档列出了 1003.1 中可重入(从线程调用安全)和非可重入的所有函数。不幸的是,我不知道任何地方都有免费的在线副本。 @ChrisDodd 我在unix-systems.org/version4 上找到了副本,我可以在第 7.1 章看到系统接口表的列表,但看不到它在哪里列出了作为原子操作的函数。不要怀疑您,但您能否分享/编辑您的答案以证明您在文档中的观点?【参考方案2】:

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

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

【讨论】:

【参考方案3】:

我看不出并行接收怎么可能完成任何事情。如果您有 3 个字节的消息,则 1 个线程可以获取第一个 2 个字节,另一个线程可以获取最后一个字节,但是您无法分辨哪个是哪个。除非您的消息只有一个字节长,否则您无法可靠地使多个线程接收任何东西。

多次发送可能工作,如果你在一个电话中发送整个消息,但我不确定。一个人可能会覆盖另一个人。这样做肯定不会有任何性能优势。

如果多个线程需要发送,你应该实现一个同步消息队列。让一个线程执行从队列中读取消息的实际发送,并让其他线程将整个消息排入队列。同样的事情也适用于接收,但接收线程必须知道消息的格式,以便正确反序列化它们。

【讨论】:

如果您使用 SOCK_DGRAM 套接字,每个 recv 将获得一个数据报;它永远不会在recvs之间拆分 @noah,我同意并行 recvs 无法完成任何事情。这就是我没有问的原因。我的问题是并行发送/接收,然后并行发送多个。您的回答确实可以深入了解并行发送。谢谢你。 @Chris 好点。我假设TCP。 @Jay您可能会澄清“我们可以并行调用发送/接收”这个问题,听起来您想并行接收。

以上是关于在同一个套接字上对发送/接收的并行调用是不是有效?的主要内容,如果未能解决你的问题,请参考以下文章

Java - UDP通过套接字发送数据..不是rec。所有数据

Python Socket接收/发送多线程

检查非阻塞发送是不是成功

paypay并行支付是不是将邮件发送到android sdk中的接收者?

c套接字发送和接收一个int而不是一个char缓冲区

socket 错误之:OSError: [WinError 10057] 由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。