2008-09-13 153 views
14

我正在用Python编写一个小型Web服务器,使用BaseHTTPServer和BaseHTTPServer.BaseHTTPRequestHandler的自定义子类。是否有可能让这个监听多个端口?如何编写python HTTP服务器以侦听多个端口?

我现在做:

class MyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 
    def doGET 
    [...] 

class ThreadingHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

server = ThreadingHTTPServer(('localhost', 80), MyRequestHandler) 
server.serve_forever() 

回答

28

把握;只需在两个不同线程的两个不同端口上启动两个不同的服务器,每个线程使用相同的处理程序。这是我刚刚编写和测试的一个完整的工作示例。如果你运行该代码,那么你就可以在两个http://localhost:1111/http://localhost:2222/

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): 
    pass 

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) 
+0

GIL可以吗? – sashab 2012-04-03 14:40:47

+1

@scrat:GIL对于这段代码无关紧要,因为这段代码大部分都是I/O绑定的,而且Python中的大部分I/O都是使用释放GIL的低级C库编写的。与大多数性能问题一样,我的建议是不要担心它,除非您已经对代码进行了基准测试并确定它确实是一个问题。 – 2012-04-03 15:24:42

4

不容易得到一个Hello World网页。你可以有两个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() 

我也认为它看起来会更加清晰让每个端口以同样的方式来处理,而不必在主线程处理一个端口和一个额外的线程,处理另一个。可以说,这可以在线程示例中修复,但是接下来使用三个线程。