gar*_*gkc 3 linux linux-networking
简单的重现 - 在一个窗口中观察顶部的进程,在另一个窗口中运行: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 ...>
Run Code Online (Sandbox Code Playgroud)
在不同的端口上设置两个侦听器 - 例如 10000 和 10001,并且两者都全速运行。
这是一个简单的示例,但我可以使用其他输入和输出来重现它 - 例如 zcatting 大文件并通过网络将它们发送到生产服务。这与输入无关,也与监听套接字无关。
那么 - 为什么我只能有一个 tcp 连接到任何给定的主动发送数据的主机/端口?
有一个独立的数据源(如果您不相信我,请随意实验),以及一个打开自己的 TCP 连接的独立进程(netstat将显示它们都打开) - 唯一的共同点是目的地(它不必须nc倾听lo- 发生任何事情)。
鉴于目的地肯定可以有多个传入套接字同时接收数据,并且源肯定可以同时向多个网络套接字发送数据,我正在努力找出争用的来源,导致只有一个管道处于活动状态一次。
免责声明:有很多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.
[...]
它的书写方式并不表明将同时接受两个连接:只有一个在前一个连接之后。
将监听netcat替换为socat(-d -d了解更多信息):
socat -d -d tcp4-listen:10000,reuseaddr,fork /dev/null
Run Code Online (Sandbox Code Playgroud)
该fork选项确保轻松并行处理:每个连接一个进程。