У меня проблемы с реализацией базового HTTPServer в Python 3.6 на Windows 10 Pro x64.
По сути, селектор, используемый в базовой реализации socketserver.serve_forever()
, использует селектор, чтобы определить, является ли сокет читаемым. Проблема в том, что после получения сервером одного запроса GET он всегда оценивается как true. Итак, давайте рассмотрим сценарий, в котором получен один запрос GET. GET обрабатывается, сокет сбрасывается, но selector.select
по-прежнему возвращает true, поэтому сервер пытается прочитать пустой сокет, вызывая его зависание и блокировку.
socketserver.serveforever:
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:
# 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.
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
while not self.__shutdown_request:
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock()
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
selector.select:
if sys.platform == 'win32':
def _select(self, r, w, _, timeout=None):
r, w, x = select.select(r, w, w, timeout)
return r, w + x, []
else:
_select = select.select
def select(self, timeout=None):
timeout = None if timeout is None else max(timeout, 0)
ready = []
try:
r, w, _ = self._select(self._readers, self._writers, [], timeout)
except InterruptedError:
return ready
r = set(r)
w = set(w)
for fd in r | w:
events = 0
if fd in r:
events |= EVENT_READ
if fd in w:
events |= EVENT_WRITE
key = self._key_from_fd(fd)
if key:
ready.append((key, events & key.events))
return ready
Это строка в selector
, которая, похоже, является проблемой. Он постоянно возвращает значение для r
после получения запроса GET один раз:
r, w, x = select.select(r, w, w, timeout)
.
** EDIT1 Основной имплиментатин, который терпит неудачу
MyServer.py
import http
from http import server
class Server(server.HTTPServer):
pass
MyRequestHandler.py
from http.server import BaseHTTPRequestHandler
import urllib
class OAuthGrantRequestHandler(BaseHTTPRequestHandler):
"""docstring"""
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
parts = urllib.parse.urlparse(self.path)
self.wfile.write(
b'<html><head><title>Authentication Status</title></head>'
b'<body><p>The authentication flow has completed.</p>')
print("Request handler completed")
return
MyTest.py
import MyServer
import MyRequestHandler
import threading
def AwaitCallback(server_class=MyServer.Server,
handler_class=MyRequestHandler.OAuthGrantRequestHandler):
"""docstring"""
server_address = ("127.0.0.1", 8080)
Httpd = server_class(server_address, handler_class)
Httpd.timeout = 200
t1 = threading.Thread(target=Httpd.serve_forever, args=(1,))
try:
t1.start()
finally:
if t1:
t1.join()
print("thread 3 terminated")
if Httpd:
Httpd.server_close()
return
AwaitCallback()
После запуска теста я просто перенаправляю localhost: 8080 в мой любимый браузер и уолла, сервер успешно отвечает, а затем блокируется.