我有一个应该从
sshd
运行的程序。它应该打印几行到标准输出,然后分叉并退出。分叉程序应该独立于 sshd
执行其任务,而不会阻塞该程序。问题是,当从终端 shell 或通过带有选项 -t
的 ssh 执行时,下面的程序可以正确运行。当终端未分配时,它会阻止 ssh 连接。
#! /usr/bin/env python3
import os, time, sys
print("Hello world", flush=True)
if os.fork()==0:
# child
sys.stdin.close()
sys.stdout.close()
sys.stderr.close()
os.setsid()
# just in case make a second fork
if os.fork()>0:
os.exit()
os.setsid()
time.sleep(30)
os.exit(0)
os.wait()
print("bye, world")
即使没有终端调用,如何让程序释放 ssh 连接?
./test-prog.py
ssh -t server ./test-prog.py
ssh server ./test-prog.py
我会从通过 ssh 连接的守护进程运行这个程序,然后退出,使分叉的子进程与 ssh 分离。 在实际应用中,该程序仅打开几个 TCP 套接字并将其端口号写入标准输出。客户端读取端口然后连接到它。
我发现在Python中
sys.stdin.close()
并没有真正关闭fd 0,关闭stdout
和stderr
也没有真正关闭fd 1和2。
ssh 在以下情况下保持连接:
pty 已开放 或
所有 fds 0,1,2(可能还有其他使用
-L
和 -R
选项传递的文件)都会关闭,即调用进程中没有 pty,并且 ssh 没有 -t
选项。
因此,关闭标准流的正确方法是将它们
dup2
改为/dev/null
,例如使用以下代码:
import os
if os.fork()==0:
# child
f_in = open("/dev/null")
f_out = open("/dev/null,"w")
os.dup2( f_in.fileno(), 0)
os.dup2( f_out.fileno(), 1)
os.dup2( 1, 2)