Bash脚本中的持久连接

9

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

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

在终端2上,我创建了一个命名管道,并运行了cat命令:
$ mkfifo fifo
$ cat > fifo

在第三个终端上,我将fifo作为客户端netcat的输入:
$ cat fifo | nc -v localhost 3000
Connection to localhost 3000 port [tcp/*] succeeded!

在第四个终端上,我可以发送任何想要的内容:
$ 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的输出等。

谢谢!


1
你好,欢迎来到 Stack Overflow!这是我见过的最好的初学者问题。 - l0b0
1个回答

3
在脚本中后台启动进程时,标准输入被重定向到“/dev/null”。这意味着第一个“cat”命令将在执行时立即读取并输出“EOF”,导致netcat在启动后立即退出。因此脚本后面的输出永远不会传递到FIFO中,因为此时没有活动的监听器。
在这种情况下,在评估“cat > fifo”时,shell派生一个子进程,将标准输入从“/dev/null”重定向,并尝试打开“fifo”进行写操作。此时,子进程仍处于阻塞的“open”调用中。请注意,“cat”直到“open”调用完成后才执行。
接下来,生成“cat fifo | nc -v localhost 3000”。 “cat”以读取方式打开“fifo”,这允许第一个子进程的阻塞“open”完成并执行第一个“cat”。
第一个“cat”继承其父文件描述符,因此其标准输入连接到“/dev/null”,因此它立即读取并输出“EOF”。第二个“cat”读取了“EOF”,并将其传递给“nc”的标准输入,导致netcat退出。
当评估“echo”语句时,“$pid1”和“$pid2”所标识的进程已经完成。由于“fifo”上不再有侦听器,因此第一个“echo”将永远阻塞。
我没有一个纯shell的解决方法,但您可以使用像perl这样的外部程序打开占位符写入器以向“fifo”写入,而不是使用shell重定向。此外,请注意,在“echo”语句(其中“kill”在netcat有机会处理输入/发送输出之前发生)后,与“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

希望这能帮到你,问得好!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接