nc -l 在后台立即关闭 (nc -l 1234 &)

Alo*_*dal 7 tcp telnet netcat

当我把这个

nc -l 12345 >nc_out
Run Code Online (Sandbox Code Playgroud)

在一个 shell 脚本中,运行它,然后使用 telnet 从其他 shell 连接,它允许我输入一些文本并让它在nc_out 中结束

但是如果我在后台启动 nc (我想稍后从同一个脚本启动 telnet):

nc -l 12345 >nc_out &
Run Code Online (Sandbox Code Playgroud)

连接立即关闭:

# telnet localhost 12345
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host
#
Run Code Online (Sandbox Code Playgroud)

将 nc_out 文件留空。

这是为什么?如何让nc正常接受连接?


笔记:

  • 在 RHEL 和 Fedora 上,ncnmap-ncat 都是这种行为,但 Debian 的nc-traditional确实接受连接并让我将数据保存到 nc_out。

  • 无论我是从同一个脚本还是不同的(SSH)会话中调用 telnet,行为都是一样的

  • 我还按照@Hauke Laging 的建议使用 strace 运行命令,并将strace 输出发布到 Pastebin

小智 7

在禁用作业控制的非交互式 shell 中执行的后台命令(就像在 shell 脚本中一样)stdin/dev/null.

sh -c 'nc -l 12345 1>nc_out & lsof -p $!'
Run Code Online (Sandbox Code Playgroud)

POSIX.1-2008 开始

2. Shell 命令语言

[...]

异步列表

如果命令由控制操作符 ('&') 终止,shell 应在子 shell 中异步执行该命令。这意味着 shell 在执行下一个命令之前不应等待命令完成。

在后台运行命令的格式为:

command1 & [command2 & ... ]
Run Code Online (Sandbox Code Playgroud)

在执行任何显式重定向之前,异步列表的标准输入应被视为分配给与 /dev/null具有相同属性的文件。如果它是交互式 shell,则不需要发生这种情况。在所有情况下,标准输入的显式重定向应覆盖此活动。

telnet客户端通过 port建立localhost与已经运行的nc命令的连接时12345,后台nc命令似乎在其标准输入上检测到 EOF 并启动其关闭过程,因为它被强制从 /dev/null 读取。read命令 ( man 2 read) 的返回值为零表示文件结束。

# strace output (from http://pastebin.com/YZHW31ef)
14:32:26 read(0, "", 2048)              = 0
14:32:26 shutdown(4, 1 /* send */)      = 0
Run Code Online (Sandbox Code Playgroud)

以下是一些保持telnet运行和通信的解决方案nc

sh -c 'nc -l 12345 0<&0 1>nc_out &'
sh -c 'nc -l 12345 0<&- 1>nc_out &'
sh -c 'tail -f /dev/null | nc -l 12345 1>nc_out &'
sh -c 'rm -f fifo; mkfifo fifo; exec 3<>fifo; nc -l 12345 0<fifo 1>nc_out &'
Run Code Online (Sandbox Code Playgroud)