当我把这个
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 上,nc和nmap-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)
2. Shell 命令语言
[...]
异步列表
如果命令由控制操作符 ('&') 终止,shell 应在子 shell 中异步执行该命令。这意味着 shell 在执行下一个命令之前不应等待命令完成。
在后台运行命令的格式为:
Run Code Online (Sandbox Code Playgroud)command1 & [command2 & ... ]
在执行任何显式重定向之前,异步列表的标准输入应被视为分配给与 /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)