python中的多线程Web服务器

时间:2012-12-30 04:20:10

标签: python multithreading http webserver

我正在尝试在python中创建多线程Web服务器,但它一次只响应一个请求,我无法弄清楚原因。你能帮帮我吗?

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

6 个答案:

答案 0 :(得分:72)

查看Doug Hellmann博客上的this帖子。

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

答案 1 :(得分:8)

我开发了一个名为ComplexHTTPServer的PIP实用程序,它是SimpleHTTPServer的多线程版本。

要安装它,您只需要:

pip install ComplexHTTPServer

使用它就像:

python -m ComplexHTTPServer [PORT]

(默认情况下,端口为8000.)

答案 2 :(得分:4)

在python3中,您可以使用以下代码(https或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()

您将发现此代码将创建一个新线程来处理每个请求。

以下生成自签名证书的命令:

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

如果您使用Flask,this blog很棒。

答案 3 :(得分:3)

这是类似多线程SimpleHTTPServer的HTTP服务器的另一个很好的例子:MultithreadedSimpleHTTPServer on GitHub

答案 4 :(得分:3)

令人惊讶的是,这些破解流媒体的解决方案获得了多少票。如果在路上可能需要流式传输,那么ThreadingMixIn和gunicorn就不好了,因为它们只是收集响应并将其作为一个单元写在最后(如果你的流是无限的,它实际上什么都不做)。

BaseHTTPServer与线程相结合的基本方法很好。但是默认的BaseHTTPServer设置会在每个侦听器上重新绑定一个新套接字,如果所有侦听器都在同一个端口上,那么它将无法在Linux中工作。在serve_forever()来电之前更改这些设置。 (就像你必须在一个线程上设置self.daemon = True来阻止ctrl-C被禁用。)

以下示例在同一端口上启动100个处理程序线程,每个处理程序都通过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)

答案 5 :(得分:0)

python3.7中的多线程https服务器

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.dates import datestr2num
from matplotlib.collections import LineCollection

y = [0, 0, 2, 2, 5, 5, 1, 1, 0, 0, 4, 4, 3, 3, 0, 0]
x ="""2016-04-18 00:00:00
2017-10-24 00:00:00
2017-10-24 00:00:00
2017-11-27 00:00:00
2017-11-27 00:00:00
2017-11-30 00:00:00
2017-11-30 00:00:00
2018-03-08 00:00:00
2018-03-08 00:00:00
2018-06-13 00:00:00
2018-06-13 00:00:00
2018-07-09 00:00:00
2018-07-09 00:00:00
2018-10-29 00:00:00
2018-10-29 00:00:00
2019-11-18 15:00:00"""
x = [datestr2num(l) for l in x.splitlines()]

segs = np.column_stack((x,y)).reshape(len(x)//2, 2, 2)
lc = LineCollection(segs)

fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
ax.xaxis_date()
plt.show()

您可以在浏览器中对其进行测试:https://localhost:8080 运行结果是: enter image description here
enter image description here 请注意,您可以生成自己的密钥文件和证书使用

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

要了解有关使用openssl创建自签名证书的详细信息:https://www.devdungeon.com/content/creating-self-signed-ssl-certificates-openssl