我想将 netcat 用作从命名管道读取数据的 TCP 服务器。为此,我做了以下事情:
步骤 1. 创建一个管道和使用它作为源的服务器
mkfifo /tmp/all.pipe
nc -k -l 8080 < /tmp/all.pipe
第 2 步. 创建一个持续读取数据的客户端:
while true; do
sleep 1;
echo "Check connection";
while IFS= read -r line; do
printf "$line";
done < /dev/tcp/localhost/8080;
done
步骤 3. 将一些数据写入管道:
echo "hello" > /tmp/all.pipe
执行这 3 个步骤后,客户端的输出为:
...
bash: connect: Connection refused
bash: /dev/tcp/localhost/8080: Connection refused
Check connection
bash: connect: Connection refused
bash: /dev/tcp/localhost/8080: Connection refused
Check connection
hello
但是,当我再次执行此后的步骤 3 时,输出没有改变。看起来它发生了,因为连接仍然处于活动状态,但新数据没有从管道传递到 nc,然后再传递到客户端。为什么?可以做些什么来实现它?
之上:
shell 尝试打开
/tmp/all.pipe
并挂起,因为还没有打开命名管道进行写入的进程。由于
nc
尚未启动,这就解释了为什么在尝试连接时bash
连接被拒绝。当你做
然后就是第一个命令被解锁的时候。管道现在已实例化。
然后在那里
echo
写入hello\n
并终止,此时管道的写入端关闭,并将nc
在其标准输入上看到文件结尾。如果您使用cat
而不是nc
,cat
将会终止。但是对于
nc
,它的 stdout 在那一点仍然到达终端并且 TCP 连接仍然有效,所以即使有一个端点已经到达输入端,它也会继续。例如,如果bash
在那个套接字上发送了一些东西,那将显示在nc
的标准输出上。当你做第二个
echo something > /tmp/all.pipe
时,asnc
没有关闭它在管道上的 fd(至少Ubuntu 上nc
的netcat-openbsd
包的情况是这样,YMMV),它确实通过了再次上线的同一个管道,但nc
已经放弃了阅读从那开始,因为它更早到达了eof。这里最简单的方法可能是在读+写模式下打开
nc
输入的管道,这样它就会立即实例化,并且一直nc
存在。为此,只需在命令行上替换
<
为:<>
nc
另请注意,第一个参数
printf
是格式,您不应该在那里有任何变量。如果要打印不带行分隔符的输入行,请使用: