我想使用 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,然后传递到客户端。为什么?可以做什么来实现它?
答案1
之上:
nc -k -l 8080 < /tmp/all.pipe
shell 尝试打开/tmp/all.pipe
但挂起,因为还没有进程打开命名管道进行写入。
既然nc
还没有开始,这就解释了为什么bash
会得到一个连接被拒绝当尝试在那里连接时。
当你这样做时
echo "hello" > /tmp/all.pipe
然后第一个命令就被解锁了。现在管道已被实例化。
然后在那里echo
写入hello\n
并终止,此时管道的写入端关闭,并且nc
将在其标准输入上看到文件结尾。如果您使用,cat
代替nc
,cat
就会终止。
但是对于nc
,它的标准输出仍然会在这一点上到达终端,并且 TCP 连接仍然处于活动状态,因此即使有一端已到达输入结束,它也会继续。例如,如果bash
在该套接字上发送某些内容,则会显示在 的 stdout 上。nc
当您执行第二个操作时echo something > /tmp/all.pipe
,因为nc
尚未关闭管道上的 fd(至少是Ubuntu 上的nc
软件包中的情况netcat-openbsd
,YMMV),它确实会通过再次上线的同一个管道,但nc
已经放弃了读取从那以后,它已经到达了 eof 较早。
这里最简单的可能是以读+写模式打开 's 输入的管道,nc
这样它就会立即实例化,并且总是与nc
生命一样长。
为此,只需在命令行上替换<
为:<>
nc
nc -k -l 8080 <> /tmp/all.pipe
另请注意,第一个参数printf
是格式,那里不应该有任何变量。如果要打印不带行分隔符的输入行,请使用:
printf %s "$line"