0

SSHトンネルを介してリモートMySQLDBと通信するには、Pythonでポートフォワーディングを使用する必要があります。paramikoパッケージをダウンロードして、ポート転送デモ(forward.py)を試してみました。非常にうまく機能しますが、自分のスクリプトに統合するのに問題があります(以下のスクリプトと同様)。メインの転送関数が呼び出されると、無限ループに入り、残りのコードは実行されません。forward.pyデモを使用して、無限ループを通過するにはどうすればよいですか?

私のスクリプト:

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
4

2 に答える 2

1

独自のスレッドで実行し、キューを使用して通信するには、ハンドラー転送コードが必要だと思います。

または、関連する呼び出しとそれが独自のループにあるものを引き出します。うーん、これがどのように機能するのか正確にはわかりません。

mysql 呼び出しをプログラム内で動作させたいですか、それとも別のプログラムから転送しますか?

于 2011-07-05T04:46:54.060 に答える
1

私は、SSH セッション管理に Paramiko を多用する Python X2Go と呼ばれる Pyhon モジュールのアップストリームの作成者です。

コード内の forward.py ファイルを見てください: http://code.x2go.org/gitweb?p=python-x2go.git;a=blob;f=x2go/forward.py

Python X2Go のコードは、サーバーとクライアントの通信、ポート転送などに Python gevent を多用しています。

ごきげんよう、マイク

于 2012-05-25T17:07:05.090 に答える