如何编写一个Python HTTP服务器以监听多个端口?
我正在用Python写一个小型的网络服务器,使用的是BaseHTTPServer和BaseHTTPServer.BaseHTTPRequestHandler的自定义子类。请问可以让这个服务器监听多个端口吗?
我现在的做法是:
class MyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def doGET
[...]
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
pass
server = ThreadingHTTPServer(('localhost', 80), MyRequestHandler)
server.serve_forever()
3 个回答
6
这事儿不太简单。你可以创建两个 ThreadingHTTPServer 的实例,然后自己写一个 serve_forever() 函数(别担心,这个函数并不复杂)。
现有的函数是:
def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown.
Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do them in
another thread.
"""
self.__serving = True
self.__is_shut_down.clear()
while self.__serving:
# XXX: Consider using another file descriptor or
# connecting to the socket to wake this up instead of
# polling. Polling reduces our responsiveness to a
# shutdown request and wastes cpu at all other times.
r, w, e = select.select([self], [], [], poll_interval)
if r:
self._handle_request_noblock()
self.__is_shut_down.set()
所以我们替换的函数大概是这样的:
def serve_forever(server1,server2):
while True:
r,w,e = select.select([server1,server2],[],[],0)
if server1 in r:
server1.handle_request()
if server2 in r:
server2.handle_request()
6
我觉得对于这么简单的事情,使用多线程有点过了。你不如用一些异步编程的方法。
这里有一个使用 Twisted 的例子:
from twisted.internet import reactor
from twisted.web import resource, server
class MyResource(resource.Resource):
isLeaf = True
def render_GET(self, request):
return 'gotten'
site = server.Site(MyResource())
reactor.listenTCP(8000, site)
reactor.listenTCP(8001, site)
reactor.run()
我还觉得让每个端口以相同的方式处理,看起来要干净很多,而不是让主线程处理一个端口,另一个线程处理另一个端口。虽然在多线程的例子中可以解决这个问题,但那样的话你就得用到三个线程了。
42
当然可以;只需要在两个不同的端口上启动两个不同的服务器,并在两个不同的线程中运行它们,这两个服务器都使用相同的处理程序。下面是一个完整的、可以运行的例子,我刚写好并测试过。如果你运行这段代码,就能在 http://localhost:1111/ 和 http://localhost:2222/ 这两个地址上看到一个“Hello World”的网页。
from threading import Thread
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write("Hello World!")
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True
def serve_on_port(port):
server = ThreadingHTTPServer(("localhost",port), Handler)
server.serve_forever()
Thread(target=serve_on_port, args=[1111]).start()
serve_on_port(2222)
更新:
这个方法在Python 3中也可以使用,但有三行代码需要稍微修改一下:
from socketserver import ThreadingMixIn
from http.server import HTTPServer, BaseHTTPRequestHandler
还有
self.wfile.write(bytes("Hello World!", "utf-8"))