Con Python Socketserver, ¿cómo puedo pasar una variable al constructor de la clase de controlador?
python-2.7 (4)
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 @aramaki).
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.
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.
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..."
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:
- Almacene la conexión como una propiedad del servidor (agregue
server.conn = conn
antes de llamar aserver_forever()
) y luego acceda a esa propiedad en EchoHandler.handler a través deself.server.conn
. - Puede sobrescribir la
finish_request
definish_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