只有一个 TCP 套接字(通过 nc)能够同时向同一主机/端口发送数据

只有一个 TCP 套接字(通过 nc)能够同时向同一主机/端口发送数据

简单的重现-在一个窗口中监视顶部的进程,在另一个窗口中运行: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选项可确保轻松进行并行处理:每个连接一个进程。

相关内容