2008-09-13 20 views
14

Estoy escribiendo un pequeño servidor web en Python, utilizando BaseHTTPServer y una subclase personalizada de BaseHTTPServer.BaseHTTPRequestHandler. ¿Es posible hacer que esto escuche en más de un puerto?¿Cómo escribo un servidor HTTP python para escuchar en varios puertos?

Lo que estoy haciendo ahora:

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

class ThreadingHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

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

Respuesta

28

Claro; simplemente inicie dos servidores diferentes en dos puertos diferentes en dos subprocesos diferentes, cada uno de los cuales usa el mismo controlador. Aquí hay un ejemplo completo y de trabajo que acabo de escribir y probar. Si se ejecuta este código, a continuación podrás conseguir una página web Hola mundo, tanto en http://localhost:1111/ y 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

¿Está bien con GIL? – sashab

+1

@scrat: El GIL no tendrá mucha importancia para este código, ya que este código se enlazará en su mayoría con E/S, y la mayoría de las E/S en Python se escriben utilizando bibliotecas C de bajo nivel que liberan el GIL. Al igual que con la mayoría de las preguntas sobre rendimiento, mi consejo es que no te preocupes, a menos que hayas evaluado tu código y determinado que en realidad es un problema. –

+0

+1 para adherirse a la biblioteca estándar :) –

4
No

fácilmente. Puede tener dos instancias de ThreadingHTTPServer, escribir su propia función serve_forever() (no se preocupe, no es una función complicada).

La función existente:

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

Así que nuestro reemplazo sería algo así como:

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

diría que el roscado por algo este sencillo es una exageración. Es mejor utilizar alguna forma de programación asincrónica.

Aquí hay un ejemplo usando 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() 

También piensa que se parece mucho más limpio que cada puerto se maneja de la misma manera, en lugar de tener el hilo principal manejar un puerto y un hilo adicional manejar el otro. Podría decirse que se puede arreglar en el ejemplo de la secuencia, pero luego está usando tres hilos.

+0

Haces algunos puntos muy buenos, y estuve tentado de aconsejar el uso de Twisted en mi respuesta. La principal ventaja de mi enfoque es que no requiere nada fuera de la biblioteca estándar. Para una aplicación real, simplemente usaría CherryPy detrás de Apache u otra cosa que no sea BaseHTTPServer. –

Cuestiones relacionadas