как мне избежать бесконечного цикла при использовании демонстрации переадресации портов paramiko?

Мне нужно использовать переадресацию портов в Python для связи с удаленной базой данных MySQL через туннель SSH. Я скачал пакет 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

person Joshua Gomez    schedule 20.05.2011    source источник
comment
Хорошо, поскольку никто, кажется, не хочет отвечать на этот вопрос, мои новые вопросы: А что насчет того, что мой первоначальный вопрос отталкивает всех остальных? Что я должен изменить, чтобы люди действительно откликнулись? Нужно ли мне перефразировать его или добавить дополнительную информацию?   -  person Joshua Gomez    schedule 15.06.2011


Ответы (2)


Я думаю, вам нужно, чтобы код переадресации обработчика работал в своем собственном потоке и использовал очереди для связи с ним.

Или вытащите соответствующие вызовы и прочее в своем собственном цикле. Хм, я не уверен, как именно это работает.

Вы хотите, чтобы ваши вызовы mysql работали с ним в вашей программе или перенаправлялись из другой программы?

person Demolishun    schedule 05.07.2011
comment
Спасибо за ваш ответ. Похоже, мне нужно научиться запускать потоки в Python. Мне не нужно, чтобы сценарий пересылки был частью моего сценария базы данных, и им не нужно взаимодействовать друг с другом. Вызовы БД отправляются на 127.0.0.1:3306, который сценарий переадресации уже перенаправляет на удаленный сервер. Я просто удивлен, что не могу найти пример этого, уже опубликованный где-то. - person Joshua Gomez; 06.07.2011
comment
Я пытался сделать это и не мог заставить его работать. Это произошло потому, что мой веб-хост отклоняет переадресацию портов. Я попытался сделать это, написав собственное приложение, которое запускается на удаленном хосте после создания SSH-соединения, но не смог заставить его работать. Я получил некоторый текст, но он не мог правильно установить связь с сервером mysql. Извините, я не могу больше помочь, так как я перестал возиться с материалом Paramiko, когда понял, что мой веб-хост является общим хостом и блокирует переадресацию портов. - person Demolishun; 01.01.2012

Я автор основного модуля 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 для связи между сервером и клиентом, переадресации портов и т. д.

Привет, Майк

person Mike Gabriel    schedule 25.05.2012
comment
Добро пожаловать в Stack Overflow. Прочтите наш часто задаваемые вопросы. Пожалуйста, не публикуйте ответы, которые являются просто ссылкой: включите в сообщение полезный контент и предоставьте ссылку для справки . Не могли бы вы включить сюда какой-нибудь код (хорошо бы 10–20 строк), демонстрирующий переадресацию портов? - person Gilles 'SO- stop being evil'; 25.05.2012