python子进程.Popen和ssh端口在后台转发

xmjla07d  于 2022-12-28  发布在  Python
关注(0)|答案(2)|浏览(146)

我需要有一个功能,基本上会模拟用户创建一个端口转发与ssh.所以,基本上应该这样工作:- execute ssh -f -N -L 10000:gateway:11000 localhost-如果该命令有输出,则显示给用户并将用户的输入作为响应- finish我在下面编写的代码几乎可以满足我的需要:

ssh_proc = Popen(['ssh', '-f', '-N', '-L', '10000:gateway:11000', 'localhost'], stdin=PIPE, stdout=PIPE)
stdoutdata, stderrdata = ssh_proc.communicate()

但问题是它从来没有完成。我看到命令被执行,转发隧道被创建,但communicate()仍然卡住。我可以用Ctrl+C打破它,并得到如下:

^CTraceback (most recent call last):
  File "sshman.py", line 278, in <module>
    add(args.remote_host, args.remote_port, args.local_port, args.local_host)
  File "sshman.py", line 125, in add
    stdoutdata, stderrdata = ssh_proc.communicate()
  File "/usr/lib64/python2.7/subprocess.py", line 740, in communicate
    return self._communicate(input)
  File "/usr/lib64/python2.7/subprocess.py", line 1256, in _communicate
    stdout, stderr = self._communicate_with_poll(input)
  File "/usr/lib64/python2.7/subprocess.py", line 1310, in _communicate_with_poll
    ready = poller.poll()
KeyboardInterrupt

因为我在ssh命令中使用了-f,所以它应该分叉连接。有没有方法在完成时中断communicate(),或者有没有更优雅的解决方案?
提前感谢您的任何意见/建议/评论。

0yycz8jy

0yycz8jy1#

我想解决办法很简单

ssh_proc = Popen(['ssh', '-f', '-N', '-L', '10000:gateway:11000', 'localhost'], stdin=PIPE, stdout=PIPE)
stat = ssh_proc.poll()
while stat == None:
    stat = ssh_proc.poll()
xqk2d5yq

xqk2d5yq2#

我在尝试设置ssh隧道时遇到了一个相关的问题,communicate()将永远挂起,我发现它从stderr和stdout读取,所以如果你的命令没有向stderr写入任何内容,那么它将挂起,因为它正在等待从stderr读取一些内容(fd = 2)。因此,作为一个解决方案,你可以使用os.set_blocking(ssh_proc.stderr.fileno(),False):

# Start the process.
ssh_proc = Popen(...)
# Wait till it's done.
ssh_proc.wait()
# Disable block for read.
os.set_blocking(ssh_proc.stderr.fileno(), False)
os.set_blocking(ssh_proc.stdout.fileno(), False)
# Read stdout and stderr.
err = ssh_proc.stderr.readlines()
out = ssh_proc.stdout.readlines()
# Print stderr and stdout.
if out:
    out = out[0]
    print(out)
if err:
    err = err[0]
    print(err)
if cmd.returncode == 0:
    return 0

这样communicate()函数就不会阻塞进程,即使没有从stdout或stderr读取任何内容。

相关问题