2012-12-30 213 views
37

我试图在python中创建多线程的web服务器,但它一次只响应一个请求,我找不出原因。你能帮我吗?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() 
+0

使用非阻塞套接字,您可以服务数千个客户端。无需为每个请求创建线程。 –

+0

@ shiplu.mokadd.im你可以请回答..你的帮助将不胜感激 –

+0

@Pilot这里需要两件事情。 'select()'和非阻塞。 Python有一个[socket](http://docs.python.org/2/library/socket.html)库。 IBM在使用select()的套接字编程中得到了一些[好文章](https://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzab6%2Frzab6xnonblock.htm)。 –

回答

56

查看this来自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() 
+8

请注意,'ThreadingMixIn'必须位于超类列表中的'HTTPServer'之前,否则它将不起作用 –

+0

伟大的斯科特你很好! +1 –

+0

[Python3文档](https://docs.python.org/3.5/library/socketserver.html#asynchronous-mixins)中的更详细示例。 – Eido95

3

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

+1

+1,这似乎是从以下脚本改编而来(或由原始作者维护):https://kdecherf.com/blog/2012/07/29/multithreaded-python-simple- http-server/ – technomalogical

+0

这不会流。更好的方法使用'BaseHTTPServer'在这里:https://stackoverflow.com/questions/46210672/ –

1

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

要安装它,所有你需要做的是:

pip install ComplexHTTPServer 

使用它很简单:

python -m ComplexHTTPServer [PORT] 

(默认情况下,端口是8000)

+0

我upvoting你的答案,因为它最终作品以及任何其他答案,其中一个不需要流的情况下。 –

+0

而你的回答更加简洁! –

1

这些突破流式传输的解决方案获得多少票数是惊人的。如果可能需要流式传输,那么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)