即使主进程结束,分叉服务也会阻止 ssh 连接

问题描述 投票:0回答:1

我有一个应该从

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 连接?

  1. 直接运行(正确运行,立即退出,留下分叉的子进程):
./test-prog.py
  1. 通过带有强制终端的 ssh 仍然可以正常工作:
ssh -t server ./test-prog.py
  1. 通过没有强制终端的 ssh 无法正常工作。它会打印这两行,然后等待 30 秒来释放 ssh:
ssh server ./test-prog.py

我会从通过 ssh 连接的守护进程运行这个程序,然后退出,使分叉的子进程与 ssh 分离。 在实际应用中,该程序仅打开几个 TCP 套接字并将其端口号写入标准输出。客户端读取端口然后连接到它。

python ssh tcp sshd setsid
1个回答
0
投票

我发现在Python中

sys.stdin.close()
并没有真正关闭fd 0,关闭
stdout
stderr
也没有真正关闭fd 1和2。

ssh 在以下情况下保持连接:

  1. pty 已开放

  2. 如果没有分配 pty,
  3. 所有 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)
© www.soinside.com 2019 - 2024. All rights reserved.