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

相關問題