web-dev-qa-db-fra.com

Serveur Web multithread en python

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()
48
user1937459

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()
73
root

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.)

10
ViCky

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.

5
g10guang

Voici un autre bon exemple d'un serveur HTTP de type SimpleHTTPServer multithread: MultithreadedSimpleHTTPServer sur GitHub .

3
GBC

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)
3
personal_cloud