С помощью python socketserver, как я могу передать переменную в конструктор класса обработчика - PullRequest
17 голосов
/ 29 июля 2011

Я бы хотел передать свое соединение с базой данных классу EchoHandler, однако я не могу понять, как это сделать, или вообще не могу получить доступ к классу EchoHandler.


class EchoHandler(SocketServer.StreamRequestHandler):
    def handle(self):
        print self.client_address, 'connected'

if __name__ == '__main__':
    conn = MySQLdb.connect (host = "10.0.0.5", user = "user", passwd = "pass", db = "database")

    SocketServer.ForkingTCPServer.allow_reuse_address = 1

    server = SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler)

    print "Server listening on localhost:4242..."
    try:
        server.allow_reuse_address
        server.serve_forever()
    except KeyboardInterrupt:
        print "\nbailing..."

Ответы [ 4 ]

25 голосов
/ 29 июля 2011

К сожалению, действительно нет простого способа получить доступ к обработчикам напрямую из-за пределов сервера.

У вас есть два варианта получения информации для экземпляров EchoHandler:

  1. Сохраните соединение как свойство сервера (добавьте server.conn = conn перед вызовом server_forever()), а затем получите доступ к этому свойству в EchoHandler.handler через self.server.conn.
  2. Вы можете перезаписать finish_request сервера и назначить значение там (вам нужно будет передать его конструктору EchoHandler и перезаписать EchoHandler .__ init__). Это решение гораздо более сложное , и оно в любом случае требует от вас сохранения соединения на сервере.

Мой вариант вашей лучшей ставки:

class EchoHandler(SocketServer.StreamRequestHandler):
    def handle(self):
        # I have no idea why you would print this but this is an example
        print( self.server.conn );
        print self.client_address, 'connected'

if __name__ == '__main__':
    SocketServer.ForkingTCPServer.allow_reuse_address = 1

    server = SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler)
    server.conn = MySQLdb.connect (host = "10.0.0.5", 
                     user = "user", passwd = "pass", db = "database")
    # continue as normal
9 голосов
/ 03 января 2013

Марк T имеет следующее слово в архиве списка питонов

В классе обработчика self.server ссылается на объект сервера, поэтому подкласс сервер и переопределите init , чтобы принять любые дополнительные параметры сервера и сохраните их как переменные экземпляра.


import SocketServer

class MyServer(SocketServer.ThreadingTCPServer):

    def __init__(self, server_address, RequestHandlerClass, arg1, arg2):
        SocketServer.ThreadingTCPServer.__init__(self, 
                                                 server_address, 
                                                 RequestHandlerClass)
        self.arg1 = arg1
        self.arg2 = arg2


class MyHandler(SocketServer.StreamRequestHandler):

    def handle(self):
        print self.server.arg1
        print self.server.arg2

1 голос
/ 21 июля 2017

Другой способ, который я считаю более питоническим, заключается в следующем:

class EchoHandler(SocketServer.StreamRequestHandler):
  def __init__(self, a, b):
    self.a = a
    self.b = b

  def __call__(self, request, client_address, server):
    h = EchoHandler(self.a, self.b)
    SocketServer.StreamRequestHandler.__init__(h, request, client_address, server)

Теперь вы можете передать экземпляр вашего обработчика в TCPServer:

SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler("aaa", "bbb"))

TCPServer обычно создает новый экземпляр EchoHandler для запроса, но в этом случае вместо конструктора будет вызываться метод __ call __ (это уже экземпляр.)

В методе call я явно делаю копию текущего EchoHandler и передаю ее суперструктору для соответствия исходной логике «один экземпляр обработчика на запрос».

Стоит взглянуть на модуль SocketServer, чтобы понять, что здесь происходит: https://github.com/python/cpython/blob/2.7/Lib/SocketServer.py

0 голосов
/ 06 ноября 2018

Я в настоящее время решал ту же проблему, но я использовал немного другое решение, я чувствую, что оно немного лучше и более общее (вдохновлено @aramaki).

В EchoHandler вам просто нужно перезаписать __init__ и указать пользовательский Creator метод.

class EchoHandler(SocketServer.StreamRequestHandler):
    def __init__(self, request, client_address, server, a, b):
        self.a = a
        self.b = b
        # super().__init__() must be called at the end
        # because it's immediately calling handle method
        super().__init__(request, client_address, server)

    @classmethod
    def Creator(cls, *args, **kwargs):
        def _HandlerCreator(request, client_address, server):
            cls(request, client_address, server, *args, **kwargs)
        return _HandlerCreator

Тогда вы можете просто вызвать метод Creator и передать все, что вам нужно.

SocketServer.ForkingTCPServer(('10.0.0.6', 4242), EchoHandler.Creator(0, "foo"))

Основное преимущество заключается в том, что таким образом вы не создаете больше экземпляров, чем необходимо, и расширяете класс более управляемым способом - вам больше не нужно изменять метод Creator.

...