0

我需要在Python中使用端口转发来通过SSH隧道与远程MySQL数据库进行通信。我下载了paramiko软件包并尝试了端口转发演示(forward.py)。它的工作原理非常好,但是我无法将它集成到我自己的脚本中(类似于下面的脚本)。当主转发函数被调用时,它进入一个无限循环,我的代码的其余部分不会执行。我如何使用forward.py演示并通过无限循环?如何在使用paramiko端口转发演示时避免无限循环?

我的脚本:

import paramiko 
import forward 
import MySQLdb 
import cfg 
import sys 

client = paramiko.SSHClient() 
client.load_system_host_keys() 
client.set_missing_host_key_policy(paramiko.WarningPolicy()) 

try: 
    client.connect(cfg.remhost, cfg.remport, username=cfg.user, password=cfg.password) 
except Exception, e: 
    print '*** Failed to connect to %s:%d: %r' % (cfg.remhost, cfg.remport, e) 
    sys.exit(1) 


try: 
    forward.forward_tunnel(3306, cfg.remhost, 3306, client.get_transport()) 
except KeyboardInterrupt: 
    print 'C-c: Port forwarding stopped.' 
    sys.exit(0) 

try: 
    db = MySQLdb.connect('127.0.0.1', cfg.dbuser, cfg.dbpass, cfg.dbname) 
except Exception, e: 
    print 'Failed to connect to database' 
    sys.exit(1) 

try: 
    cursor = self.db.cursor(MySQLdb.cursors.DictCursor) 
    sql = 'SELECT * FROM ' + cfg.dbtable 
    cursor.execute(sql) 
    results = cursor.fetchall() 
    print str(len(results)) 
except Exception, e: 
    print 'Failed to query database' 
    sys.exit(1) 

这里是forward.py演示代码的主要块:

class ForwardServer (SocketServer.ThreadingTCPServer): 
    daemon_threads = True 
    allow_reuse_address = True 


class Handler (SocketServer.BaseRequestHandler): 

    def handle(self): 
     try: 
      chan = self.ssh_transport.open_channel('direct-tcpip', 
                (self.chain_host, self.chain_port), 
                self.request.getpeername()) 
     except Exception, e: 
      verbose('Incoming request to %s:%d failed: %s' % (self.chain_host, 
                   self.chain_port, 
                   repr(e))) 
      return 
     if chan is None: 
      verbose('Incoming request to %s:%d was rejected by the SSH server.' % 
        (self.chain_host, self.chain_port)) 
      return 

     verbose('Connected! Tunnel open %r -> %r -> %r' % (self.request.getpeername(), 
                  chan.getpeername(), (self.chain_host, self.chain_port))) 
     while True: 
      r, w, x = select.select([self.request, chan], [], []) 
      if self.request in r: 
       data = self.request.recv(1024) 
       if len(data) == 0: 
        break 
       chan.send(data) 
      if chan in r: 
       data = chan.recv(1024) 
       if len(data) == 0: 
        break 
       self.request.send(data) 
     chan.close() 
     self.request.close() 
     verbose('Tunnel closed from %r' % (self.request.getpeername(),)) 


def forward_tunnel(local_port, remote_host, remote_port, transport): 
    # this is a little convoluted, but lets me configure things for the Handler 
    # object. (SocketServer doesn't give Handlers any way to access the outer 
    # server normally.) 
    class SubHander (Handler): 
     chain_host = remote_host 
     chain_port = remote_port 
     ssh_transport = transport 
    ForwardServer(('', local_port), SubHander).serve_forever() 


def verbose(s): 
    if g_verbose: 
     print s 
+1

好的,因为没有人想回答这个问题,所以我的新问题是:我原来的问题是什么让别人失望?我应该改变什么以便人们能够真正回应?我是否需要更改它或添加更多信息? – 2011-06-15 17:49:05

回答

1

我认为你需要处理程序前的代码在自己的线程和使用运行队列与它通信。

或者拔出相关的电话和它在你自己的循环中的东西。嗯,我不确定这是如何工作的。

你想让你的mysql调用在你的程序中使用它,或从其他程序转发吗?

+0

感谢您的回复。看起来我需要学习如何在Python中运行线程。我不需要转发脚本成为我的数据库脚本的一部分,他们也不需要彼此进行通信。数据库调用发送到127.0.0.1:3306,转发脚本已经转发到远程服务器。我很惊讶,我找不到已经发布到某个地方的例子。 – 2011-07-06 13:59:40

+0

我试图做到这一点,并不能得到它的工作。这是因为我的网络主机拒绝端口转发。我尝试通过编写自己的应用程序来完成此操作,该应用程序在创建SSH连接后在远程主机上运行,​​但无法使其运行。我确实收到了一些文字,但它无法正确地与mysql服务器握手。抱歉,当我意识到我的虚拟主机是共享主机并阻止端口转发时,我停止了与Paramiko的混合操作,因此无法提供更多帮助。 – Demolishun 2012-01-01 09:34:32

1

我是Pyhon模块的上游作者,名为Python X2Go,它大量使用Paramiko进行SSH会话管理。

请看看在代码中forward.py文件: http://code.x2go.org/gitweb?p=python-x2go.git;a=blob;f=x2go/forward.py

的Python X2Go的大量代码使用Python GEVENT用于服务器 - 客户端通信,端口转发等

映入眼帘, Mike

+1

欢迎使用堆栈溢出。请阅读我们的[常见问题]。 [请不要发布只是链接的答案](http://stackoverflow.com/questions/how-to-answer):在您的文章中包含有用的内容,并提供链接以供参考。在这里,你是否可以包含一些代码(10-20行很棒)来演示端口转发? – Gilles 2012-05-25 18:24:24