Con Python Socketserver, ¿cómo puedo pasar una variable al constructor de la clase de controlador?

Me gustaría pasar la conexión de mi base de datos a la clase EchoHandler, sin embargo, no puedo averiguar cómo hacerlo o acceder a la clase EchoHandler.


 clase EchoHandler (SocketServer.StreamRequestHandler):
     def manejar (uno mismo):
         imprimir self.client_address, 'conectado'

 si __name__ == '__main__':
     conn = MySQLdb.connect (host = "10.0.0.5", usuario = "usuario", passwd = "pass", db = "base de datos")

     SocketServer.ForkingTCPServer.allow_reuse_address = 1

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

     Imprimir "Servidor escuchando en localhost: 4242 ..."
     tratar:
         server.allow_reuse_address
         server.serve_forever ()
     excepto KeyboardInterrupt:
         imprimir "\ nbailing ..."

Desafortunadamente, realmente no hay una manera fácil de acceder a los manejadores directamente desde fuera del servidor.

Tiene dos opciones para obtener la información de las instancias de EchoHandler:

  1. Almacene la conexión como una propiedad del servidor (agregue server.conn = conn antes de llamar a server_forever() ) y luego acceda a esa propiedad en EchoHandler.handler a través de self.server.conn .
  2. Puede sobrescribir la finish_request de finish_request del servidor y asignar el valor allí (tendría que pasarlo al constructor de EchoHandler y sobrescribir a EchoHandler .__ init__). Esa es una solución mucho más complicada y prácticamente requiere que almacenes la conexión en el servidor de todos modos.

Mi opción de su mejor apuesta:

 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 

Mark T dice lo siguiente en el archivo de la lista de python

En la clase de manejador, self.server se refiere al objeto del servidor, por lo tanto, haga una subclase del servidor y anule a init para tomar cualquier parámetro adicional del servidor y almacenarlos como variables de instancia.

 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 

Otra forma, que creo más pirónica, es hacer lo siguiente:

 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) 

Ahora puede dar una instancia de su controlador al TCPServer:

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

El TCPServer normalmente crea una nueva instancia de EchoHandler por solicitud, pero en este caso, se llamará al método __call__ en lugar del constructor (ya es una instancia).

En el método de llamada , explícitamente hago una copia del EchoHandler actual y lo paso al súper constructor para cumplir con la lógica original de “una instancia de controlador por solicitud”.

Vale la pena echar un vistazo al módulo SocketServer para comprender lo que sucede aquí: https://github.com/python/cpython/blob/2.7/Lib/SocketServer.py

Actualmente estaba resolviendo el mismo problema, pero utilicé una solución ligeramente diferente, creo que es un poco más agradable y más general (inspirado en @atwigki).

En EchoHandler solo tiene que sobrescribir __init__ y especificar el método de Creator personalizado.

 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 

Entonces puedes simplemente llamar al método Creator y pasar todo lo que necesites.

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

El beneficio principal es que de esta manera no está creando más instancias de las necesarias y está extendiendo la clase de una manera más manejable, ya que no necesita cambiar el método del Creator nunca más.