J'essaie de créer un serveur Web multithread en python, mais il ne répond qu'à une demande à la fois et je ne peux pas comprendre pourquoi. Pouvez-vous m'aider s'il vous plaît?
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from time import sleep
class ThreadingServer(ThreadingMixIn, HTTPServer):
pass
class RequestHandler(SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/plain')
sleep(5)
response = 'Slept for 5 seconds..'
self.send_header('Content-length', len(response))
self.end_headers()
self.wfile.write(response)
ThreadingServer(('', 8000), RequestHandler).serve_forever()
Vérifiez ce article du blog de Doug Hellmann.
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from SocketServer import ThreadingMixIn
import threading
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
message = threading.currentThread().getName()
self.wfile.write(message)
self.wfile.write('\n')
return
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread."""
if __== '__main__':
server = ThreadedHTTPServer(('localhost', 8080), Handler)
print 'Starting server, use <Ctrl-C> to stop'
server.serve_forever()
J'ai développé un utilitaire PIP appelé ComplexHTTPServer qui est une version multi-thread de SimpleHTTPServer.
Pour l'installer, il vous suffit de:
pip install ComplexHTTPServer
Son utilisation est aussi simple que:
python -m ComplexHTTPServer [PORT]
(Par défaut, le port est 8000.)
En python3, vous pouvez utiliser le code ci-dessous (https ou http):
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
import threading
USE_HTTPS = True
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b'Hello world\t' + threading.currentThread().getName().encode() + b'\t' + str(threading.active_count()).encode() + b'\n')
class ThreadingSimpleServer(ThreadingMixIn, HTTPServer):
pass
def run():
server = ThreadingSimpleServer(('0.0.0.0', 4444), Handler)
if USE_HTTPS:
import ssl
server.socket = ssl.wrap_socket(server.socket, keyfile='./key.pem', certfile='./cert.pem', server_side=True)
server.serve_forever()
if __== '__main__':
run()
Vous comprendrez que ce code créera un nouveau fil pour traiter chaque demande.
Commande ci-dessous pour générer un certificat auto-signé:
openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365
Si vous utilisez Flask, ce blog est super.
Voici un autre bon exemple d'un serveur HTTP de type SimpleHTTPServer multithread: MultithreadedSimpleHTTPServer sur GitHub .
Il est étonnant de voir combien de votes ces solutions qui interrompent le streaming obtiennent. Si le streaming peut être nécessaire sur la route, alors ThreadingMixIn
et gunicorn ne sont pas bons car ils collectent simplement la réponse et l'écrivent comme une unité à la fin (ce qui en fait ne fait rien si votre flux est infini).
Votre approche de base consistant à combiner BaseHTTPServer
avec des threads est correcte. Mais les paramètres par défaut BaseHTTPServer
relient une nouvelle socket à chaque écouteur, ce qui ne fonctionnera pas sous Linux si tous les écouteurs sont sur le même port. Modifiez ces paramètres avant l'appel serve_forever()
. (Tout comme vous devez définir self.daemon = True
sur un thread pour empêcher la désactivation de ctrl-C.)
L'exemple suivant lance 100 threads de gestionnaire sur le même port, chaque gestionnaire démarrant via BaseHTTPServer
.
import time, threading, socket, SocketServer, BaseHTTPServer
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
if self.path != '/':
self.send_error(404, "Object not found")
return
self.send_response(200)
self.send_header('Content-type', 'text/html; charset=utf-8')
self.end_headers()
# serve up an infinite stream
i = 0
while True:
self.wfile.write("%i " % i)
time.sleep(0.1)
i += 1
# Create ONE socket.
addr = ('', 8000)
sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(addr)
sock.listen(5)
# Launch 100 listener threads.
class Thread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
self.daemon = True
self.start()
def run(self):
httpd = BaseHTTPServer.HTTPServer(addr, Handler, False)
# Prevent the HTTP server from re-binding every handler.
# https://stackoverflow.com/questions/46210672/
httpd.socket = sock
httpd.server_bind = self.server_close = lambda self: None
httpd.serve_forever()
[Thread(i) for i in range(100)]
time.sleep(9e9)