简单的重现-在一个窗口中监视顶部的进程,在另一个窗口中运行:nc -lkp 10000 > /dev/null & ( head -50000000 /dev/urandom | nc -N 127.0.0.1 10000 ) & ( head -50000000 /dev/urandom | nc -N 127.0.0.1 10000 )
观察到只有一个head
进程nc
正在主动使用 CPU。
将 strace 附加到head
不活动的那个 - 查看它是否在写入时停滞,例如:
strace: Process 589084 attached
write(1, "\264\347\270\26\27\24'BRb^\353\302\36@\216\17V\210*n\252`\353\330\351\276\2\250\330\350\217"..., 4096^Cstrace: Process 589084 detached
<detached ...>
在不同的端口上设置两个监听器 - 例如 10000 和 10001,并且都全速运行。
这是一个简单的例子,但我可以用其他输入和输出重现它 - 例如 zcatting 大文件并通过网络将它们发送到生产服务。这与输入无关,也与监听套接字无关。
那么 - 为什么我只能与任何给定的主机/端口建立一个 TCP 连接来主动发送数据?
有一个独立的数据源(如果您不相信我,请随意尝试),以及一个打开其自己的 tcp 连接的独立进程(netstat
将显示它们都打开) - 唯一的共同点是目的地(不必是监听nc
-lo
任何事情都可以发生)。
鉴于目标肯定可以有多个传入套接字同时接收数据,并且源肯定可以同时将数据发送到多个网络套接字,我很难弄清楚争用来自哪里,导致一次只有一个管道处于活动状态。
答案1
免责声明:有很多nc
变体。假设-k
它是 OpenBSD 变体。每个nc
变体都有自己的优势。
nc
不适合做这项工作:nc -lkp 10000
它将同时管理一个连接,因为它不会分叉,尽管使用poll(2)
从不 使用,但accept(2)
直到第一个连接处理完成,它才会对第二个传入连接使用:这保证了第二个连接将不会被处理。如果还有几个,它们将开始停留在SYN-SENT
状态中,因为nc -lkp 10000
使用 1 作为listen(2)
积压:这不是随机选择。这可以通过strace
在正在运行的nc -lkp 10000
进程上使用来检查。
这关于的文档-k
选项也同样如此:
-k
连接完成时,听另一个。需要
-l
。
[...]
它的写法并不意味着会同时接受两个连接:只有一个连接落后于前一个。
更换听力网猫与socat
(-d -d
获取更多信息):
socat -d -d tcp4-listen:10000,reuseaddr,fork /dev/null
该fork
选项可确保轻松进行并行处理:每个连接一个进程。