Как остановить BaseHTTPServer.serve_forever() в подклассе BaseHTTPRequestHandler?
Я запускаю свой HTTPServer
в отдельном потоке (используя модуль потоковой передачи, который не имеет возможности остановить потоки...) и хочет прекратить подавать запросы, когда основной поток также отключается.
В документации на Python указано, что BaseHTTPServer.HTTPServer
является подклассом SocketServer.TCPServer
, который поддерживает метод shutdown
, но он отсутствует в HTTPServer
.
Весь модуль BaseHTTPServer
имеет очень мало документации: (
Ответы
Ответ 1
Я должен начать с того, что "я, вероятно, не сделал бы этого сам, но у меня было в прошлом". Метод serve_forever (из SocketServer.py) выглядит следующим образом:
def serve_forever(self):
"""Handle one request at a time until doomsday."""
while 1:
self.handle_request()
Вы можете заменить (в подклассе) while 1
на while self.should_be_running
и изменить это значение из другого потока. Что-то вроде:
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()
Изменить: я выкопал фактический код, который я использовал в то время:
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()
Ответ 2
В моей установке python 2.6 я могу вызвать ее на базовом TCPServer - она все еще находится внутри вашего HTTPServer
:
TCPServer.shutdown
>>> import BaseHTTPServer
>>> h=BaseHTTPServer.HTTPServer(('',5555), BaseHTTPServer.BaseHTTPRequestHandler)
>>> h.shutdown
<bound method HTTPServer.shutdown of <BaseHTTPServer.HTTPServer instance at 0x0100D800>>
>>>
Ответ 3
Я думаю, вы можете использовать [serverName].socket.close()
Ответ 4
Другим способом сделать это на основе http://docs.python.org/2/library/basehttpserver.html#more-examples является: вместо serve_forever(), продолжать работать до тех пор, пока выполняется условие, с сервером проверяя состояние до и после каждого запроса. Например:
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()
Ответ 5
В python 2.7 вызов shutdown() работает, но только если вы обслуживаете через serve_forever, потому что он использует async select и цикл опроса. Выполнение собственного цикла с помощью handle_request() по иронии судьбы исключает эту функциональность, поскольку подразумевает немой блокирующий вызов.
С SocketServer.py BaseServer:
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()
Вот часть моего кода для блокировки выключения из другого потока, используя событие для ожидания завершения:
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")
Ответ 6
Контуры событий заканчиваются на SIGTERM, Ctrl + C или когда вызывается shutdown()
.
server_close()
необходимо вызвать после server_forever()
, чтобы закрыть прослушивающий сокет.
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()
Простой сервер останавливается с действием пользователя (SIGTERM, Ctrl + C,...):
server = StoppableHTTPServer(("127.0.0.1", 8080),
http.server.BaseHTTPRequestHandler)
server.run()
Сервер работает в потоке:
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()
Ответ 7
Я пробовал все вышеперечисленное решение и в конечном итоге имел проблему "когда-то" - как-то это на самом деле не делал этого, поэтому я закончил тем самым грязное решение, которое все время работало для меня:
Если все выше не выполняется, то грубая сила убивает ваш поток, используя что-то вроде этого:
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)