Bash 脚本中的持久连接

Persistent connection in Bash script

我正在尝试使用 bash 创建持久连接。在终端 1 上,我保留了一个 netcat 运行ning 作为服务器:

$ nc -vlkp 3000
Listening on [0.0.0.0] (family 0, port 3000)

在 2 号航站楼,我创建了一个 fifo 并养了一只猫:

$ mkfifo fifo
$ cat > fifo

在终端 3 上,我将 fifo 作为客户端 netcat 的输入:

$ cat fifo | nc -v localhost 3000
Connection to localhost 3000 port [tcp/*] succeeded!

在 4 号航站楼,我想发送什么就发送什么:

$ echo command1 > fifo
$ echo command2 > fifo
$ echo command3 > fifo

返回终端 1,我看到正在接收的命令:

$ nc -vlkp 3000
Listening on [0.0.0.0] (family 0, port 3000)
Connection from [127.0.0.1] port 3000 [tcp/*] accepted (family 2, sport 41722)
command1
command2
command3

所以,一切正常。但是当我把它放在脚本中时(我称之为 fifo.sh),bash 无法写入 fifo:

在终端 1 上,相同的侦听服务器:

$ nc -vlkp 3000
Listening on [0.0.0.0] (family 0, port 3000)

在终端 2 上,我 运行 脚本:

#!/bin/bash

rm -f fifo
mkfifo fifo
cat > fifo &
pid1=$!
cat fifo | nc -v localhost 3000 &
pid2=$!

echo sending...
echo comando1 > fifo
echo comando2 > fifo
echo comando3 > fifo

kill -9 $pid1 $pid2

终端2的输出是:

$ ./fifo.sh 
Connection to localhost 3000 port [tcp/*] succeeded!
sending...

在 1 号航站楼上,我只看到连接。没有命令:

$ nc -vlkp 3000
Listening on [0.0.0.0] (family 0, port 3000)
Connection from [127.0.0.1] port 3000 [tcp/*] accepted (family 2, sport 42191)
Connection closed, listening again.

知道为什么它只能交互工作吗?或者有没有其他方法可以仅使用 Bash 创建持久连接?我不想使用 Expect,因为我有一个更大的 Bash 脚本,它在发送 command1 后执行一些工作,而 command2 取决于 command1 输出等。

谢谢!

当脚本在后台启动进程时,标准输入从 /dev/null 重定向。这意味着第一个 cat 命令将在执行后立即读取并发出 EOF ,这将导致 netcat 在启动后立即退出,因此脚本后面的输出永远不会进入 fifo,因为当时没有活跃的听众。

在这种情况下,当评估 cat > fifo 时,shell 派生一个 child 进程,重定向来自 /dev/null 的标准输入,并尝试打开 [=16] =] 写。此时 child 仍处于阻塞 open 调用中。请注意,cat 直到 open 调用完成后才会执行。

接下来,生成cat fifo | nc -v localhost 3000cat 打开 fifo 进行读取,这允许第一个 child 的阻塞 open 完成并执行第一个 cat

第一个 cat 继承了其 parent 的文件描述符,因此其标准输入附加到 /dev/null,因此它立即读取并发出 EOF。第二个 cat 读取 EOF 并将其传递给 nc 的标准输入,这会导致 netcat 退出。

在评估 echo 语句时,由 $pid1$pid2 标识的进程已完成。由于 fifo 上不再有监听器,第一个 echo 将永远阻塞。


我没有 pure-shell 修复程序,但您可以使用 perl 等外部程序将占位符编写器打开到 fifo 而不是使用 shell 重定向。另外,请注意在 echo 语句之后有一个 nc 的竞争(其中 kill 发生在 netcat 有机会处理 input/send 输出之前),所以这里我在 cat | nc 表达式后添加了一个延迟。几乎肯定有更好的解决方案,但这是我想出的:

#!/bin/bash

rm -f fifo
mkfifo fifo
perl -e 'open(my $fh, ">", "fifo"); sleep 3600 while 1' &
pid1=$!
cat fifo | nc -v localhost 3000 &
pid2=$!

sleep 2

echo sending...
echo comando1 > fifo
echo comando2 > fifo
echo comando3 > fifo

kill -9 $pid1 $pid2

希望这对您有所帮助,好问题!