通过ssh隧道传输TCP端口而不阻塞

3 投票
1 回答
929 浏览
提问于 2025-04-16 20:03

我正在尝试通过pexpect设置一个ssh隧道,使用以下代码:

#!/bin/env python2.4

import pexpect, sys
child = pexpect.spawn('ssh -CfNL 0.0.0.0:3306:127.0.0.1:3306 user@server.com')
child.logfile = sys.stdout
while True:
    code = child.expect([
        'Are you sure you want to continue connecting \(yes/no\)\?',
        'password:',
        pexpect.EOF,
        pexpect.TIMEOUT
    ])
    if code == 0:
        child.sendline('yes')
    elif code == 1:
        child.sendline('passwordhere')
    elif code == 2:
        print ".. EOF"
        break
    elif code == 3:
        print ".. Timeout"
        break

我希望在发送完密码并成功建立ssh隧道后,while循环能够退出,这样我就可以继续处理其他业务逻辑。

但是,上面的代码会在ssh隧道建立后仍然阻塞,直到超时(大约30秒)。

有没有人能给我一些建议,告诉我怎么避免这种阻塞?

1 个回答

3

我觉得最简单的解决办法是使用ssh主机密钥认证,然后把ssh放到后台运行,方法是加上&。这其实是个很基础的做法,但你可以进一步改进,比如在完成后结束这个进程。另外,注意我在你的ssh参数中加了-n,因为我们是把这个进程放到后台。

import subprocess

USER = 'user'
HOST = 'server.com'
cmd = r"""ssh -CfNnL 0.0.0.0:3306:127.0.0.1:3306 %s@%s &""" % (USER, HOST)
subcmd = cmd.split(' ')
retval = subprocess.Popen(subcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stat = retval.poll()
while stat == None:
    stat = retval.poll()
print "ssh in background"

最后,如果你的ssh_config里还没有ServerAliveInterval这个设置,可以考虑这样调用sshssh -o ServerAliveInterval=30 <other_options_and_args>。这样可以确保你尽快发现连接丢失,并且防止在不活动时被网络地址转换(NAT)机制给断掉。

撰写回答