【问题标题】:Persistent connection in Bash scriptBash 脚本中的持久连接
【发布时间】:2015-02-14 08:00:39
【问题描述】:

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

$ 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 的输出等。

谢谢!

【问题讨论】:

  • 您好,欢迎来到 Stack Overflow!这是我见过的最好的初学者问题。

标签: bash fifo netcat


【解决方案1】:

当一个进程在脚本的后台启动时,标准输入从/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 重定向。另外,请注意ncecho 语句之后开始存在竞争(kill 发生在 netcat 有机会处理输入/发送输出之前),所以这里我在@987654350 之后添加了延迟@ 表达。几乎可以肯定有更好的解决方案,但这是我想出的:

#!/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

希望这有帮助,好问题!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-02
    • 1970-01-01
    • 1970-01-01
    • 2021-01-09
    • 2017-07-12
    • 2016-11-26
    相关资源
    最近更新 更多