simpleserver servidor modulenotfounderror httpsimpleserver create python http basehttpserver

python - servidor - Cómo detener BaseHTTPServer.serve_forever() en una subclase BaseHTTPRequestHandler?



python simplehttpserver 8080 (7)

Estoy ejecutando mi HTTPServer en un subproceso separado (utilizando el módulo de subprocesamiento que no tiene forma de detener subprocesos ...) y quiero dejar de atender solicitudes cuando el hilo principal también se apaga.

La documentación de Python indica que BaseHTTPServer.HTTPServer es una subclase de SocketServer.TCPServer , que admite un método de shutdown , pero falta en HTTPServer .

Todo el módulo BaseHTTPServer tiene muy poca documentación :(


Debería comenzar diciendo que "probablemente yo no haría esto yo mismo, pero lo hice en el pasado". El método serve_forever (desde SocketServer.py) tiene el siguiente aspecto:

def serve_forever(self): """Handle one request at a time until doomsday.""" while 1: self.handle_request()

Podría reemplazar (en la subclase) while 1 con while self.should_be_running , y modificar ese valor desde un hilo diferente. Algo como:

def stop_serving_forever(self): """Stop handling requests""" self.should_be_running = 0 # Make a fake request to the server, to really force it to stop. # Otherwise it will just stop on the next request. # (Exercise for the reader.) self.make_a_fake_request_to_myself()

Editar: desenterré el código real que usaba en ese momento:

class StoppableRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer): stopped = False allow_reuse_address = True def __init__(self, *args, **kw): SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, *args, **kw) self.register_function(lambda: ''OK'', ''ping'') def serve_forever(self): while not self.stopped: self.handle_request() def force_stop(self): self.server_close() self.stopped = True self.create_dummy_request() def create_dummy_request(self): server = xmlrpclib.Server(''http://%s:%s'' % self.server_address) server.ping()


En mi instalación de Python 2.6, puedo invocarlo en el TCPServer subyacente; aún está allí dentro de su HTTPServer :

TCPServer.shutdown >>> import BaseHTTPServer >>> h=BaseHTTPServer.HTTPServer(('''',5555), BaseHTTPServer.BaseHTTPRequestHandler) >>> h.shutdown <bound method HTTPServer.shutdown of <BaseHTTPServer.HTTPServer instance at 0x0100D800>> >>>


Creo que puedes usar [serverName].socket.close()


Otra forma de hacerlo, basada en http://docs.python.org/2/library/basehttpserver.html#more-examples , es: en lugar de serve_forever (), seguir sirviendo mientras se cumpla una condición, con el servidor que verifica la condición antes y después de cada solicitud. Por ejemplo:

import CGIHTTPServer import BaseHTTPServer KEEP_RUNNING = True def keep_running(): return KEEP_RUNNING class Handler(CGIHTTPServer.CGIHTTPRequestHandler): cgi_directories = ["/cgi-bin"] httpd = BaseHTTPServer.HTTPServer(("", 8000), Handler) while keep_running(): httpd.handle_request()


En python 2.7, la llamada shutdown () funciona pero solo si está sirviendo a través de serve_forever, porque usa la selección async y un bucle de sondeo. Ejecutar su propio bucle con handle_request () irónicamente excluye esta funcionalidad porque implica una llamada de bloqueo tonta.

Desde BaseServer de SocketServer.py:

def serve_forever(self, poll_interval=0.5): """Handle one request at a time until shutdown. Polls for shutdown every poll_interval seconds. Ignores self.timeout. If you need to do periodic tasks, do them in another thread. """ self.__is_shut_down.clear() try: while not self.__shutdown_request: # XXX: Consider using another file descriptor or # connecting to the socket to wake this up instead of # polling. Polling reduces our responsiveness to a # shutdown request and wastes cpu at all other times. r, w, e = select.select([self], [], [], poll_interval) if self in r: self._handle_request_noblock() finally: self.__shutdown_request = False self.__is_shut_down.set()

Heres parte de mi código para hacer un bloqueo de cierre de otro hilo, usando un evento para esperar la finalización:

class MockWebServerFixture(object): def start_webserver(self): """ start the web server on a new thread """ self._webserver_died = threading.Event() self._webserver_thread = threading.Thread( target=self._run_webserver_thread) self._webserver_thread.start() def _run_webserver_thread(self): self.webserver.serve_forever() self._webserver_died.set() def _kill_webserver(self): if not self._webserver_thread: return self.webserver.shutdown() # wait for thread to die for a bit, then give up raising an exception. if not self._webserver_died.wait(5): raise ValueError("couldn''t kill webserver")


Probé todas las posibles soluciones anteriores y terminé teniendo un problema de "alguna vez", de alguna manera realmente no lo hice, así que terminé creando una solución sucia que funcionó todo el tiempo para mí:

Si todo lo anterior falla, entonces la fuerza bruta mata tu hilo usando algo como esto:

import subprocess cmdkill = "kill $(ps aux|grep ''<name of your thread> true''|grep -v ''grep''|awk ''{print $2}'') 2> /dev/null" subprocess.Popen(cmdkill, stdout=subprocess.PIPE, shell=True)


Los bucles de eventos finalizan en SIGTERM, Ctrl + C o cuando se llama a shutdown() .

server_close() debe llamarse después de server_forever() para cerrar el socket de escucha.

import http.server class StoppableHTTPServer(http.server.HTTPServer): def run(self): try: self.serve_forever() except KeyboardInterrupt: pass finally: # Clean-up server (close socket, etc.) self.server_close()

Servidor simple que se puede detener con la acción del usuario (SIGTERM, Ctrl + C , ...):

server = StoppableHTTPServer(("127.0.0.1", 8080), http.server.BaseHTTPRequestHandler) server.run()

Servidor que se ejecuta en un hilo:

import threading server = StoppableHTTPServer(("127.0.0.1", 8080), http.server.BaseHTTPRequestHandler) # Start processing requests thread = threading.Thread(None, server.run) thread.start() # ... do things ... # Shutdown server server.shutdown() thread.join()