Multithreaded webserver in python

Ik probeer een multithreaded webserver in python te maken, maar deze reageert maar op één verzoek tegelijk en ik begrijp niet waarom. Kun je me alsjeblieft helpen?

#!/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()

Antwoord 1, autoriteit 100%

Controleer ditbericht van de blog van 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 __name__ == '__main__':
    server = ThreadedHTTPServer(('localhost', 8080), Handler)
    print 'Starting server, use <Ctrl-C> to stop'
    server.serve_forever()

Antwoord 2, autoriteit 22%

Ik heb een PIP-hulpprogramma ontwikkeld met de naam ComplexHTTPServer, een versie met meerdere threads van SimpleHTTPServer.

Om het te installeren, hoeft u alleen het volgende te doen:

pip install ComplexHTTPServer

Het gebruik ervan is zo eenvoudig als:

python -m ComplexHTTPServer [PORT]

(Standaard is de poort 8000.)


Antwoord 3, autoriteit 13%

In python3 kun je de onderstaande code gebruiken (https of 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 __name__ == '__main__':
    run()

Je zult ontdekken dat deze code een nieuwe thread zal maken om elk verzoek af te handelen.

Opdracht hieronder om zelfondertekencertificaat te genereren:

openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365

Als je Flask gebruikt, deze blogis geweldig.


Antwoord 4, autoriteit 10%

Het is verbazingwekkend hoeveel stemmen deze oplossingen die streaming breken krijgen. Als streaming onderweg misschien nodig is, dan zijn ThreadingMixInen gunicorn niet goed omdat ze gewoon het antwoord verzamelen en het aan het einde als een eenheid schrijven (wat eigenlijk niets doet als je stream oneindig is) .

Uw basisbenadering van het combineren van BaseHTTPServermet threads is prima. Maar de standaard BaseHTTPServer-instellingen binden opnieuw een nieuwe socket op elke luisteraar, wat niet zal werken in Linux als alle luisteraars op dezelfde poort zitten. Wijzig die instellingen vóór de aanroep serve_forever(). (Net zoals je self.daemon = Truemoet instellen op een thread om te voorkomen dat ctrl-C wordt uitgeschakeld.)

Het volgende voorbeeld start 100 handlerthreads op dezelfde poort, waarbij elke handler wordt gestart 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)

Antwoord 5, autoriteit 2%

Een multithreaded https-server in python3.7

from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
import threading
import ssl
hostName = "localhost"
serverPort = 8080
class MyServer(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(bytes("<html><head><title>https://pythonbasics.org</title></head>", "utf-8"))
        self.wfile.write(bytes("<p>Request: %s</p>" % self.path, "utf-8"))
        self.wfile.write(bytes("<p>Thread: %s</p>" % threading.currentThread().getName(), "utf-8"))
        self.wfile.write(bytes("<p>Thread Count: %s</p>" % threading.active_count(), "utf-8"))
        self.wfile.write(bytes("<body>", "utf-8"))
        self.wfile.write(bytes("<p>This is an example web server.</p>", "utf-8"))
        self.wfile.write(bytes("</body></html>", "utf-8"))
class ThreadingSimpleServer(ThreadingMixIn,HTTPServer):
    pass
if __name__ == "__main__":
    webServer = ThreadingSimpleServer((hostName, serverPort), MyServer)
    webServer.socket = ssl.wrap_socket(webServer.socket, keyfile='./privkey.pem',certfile='./certificate.pem', server_side=True)
    print("Server started http://%s:%s" % (hostName, serverPort))
    try:
        webServer.serve_forever()
    except KeyboardInterrupt:
        pass
    webServer.server_close()
    print("Server stopped.")

je kunt het testen in een browser: https://localhost:8080
het loopresultaat is:
voer hier de afbeeldingsbeschrijving in
voer hier de afbeeldingsbeschrijving in
herinner eraan dat u uw eigen sleutelbestand en certificaatgebruik kunt genereren

$openssl req -newkey rsa:2048  -keyout privkey.pem -x509 -days 36500 -out certificate.pem

Om details te leren over het maken van zelfondertekend certificaat met OpenSSL: https://www.devdungeon.com/content/creating-self-signed-ssl-certificates-Opensl

Other episodes