2008-09-13 16 views
14

J'écris un petit serveur web en Python, en utilisant BaseHTTPServer et une sous-classe personnalisée de BaseHTTPServer.BaseHTTPRequestHandler. Est-il possible de faire cette écoute sur plus d'un port?Comment écrire un serveur HTTP python pour écouter sur plusieurs ports?

Ce que je fais maintenant:

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

class ThreadingHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

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

Répondre

28

Bien sûr; Il suffit de démarrer deux serveurs différents sur deux ports différents dans deux threads différents qui utilisent chacun le même gestionnaire. Voici un exemple de travail complet que je viens d'écrire et de tester. Si vous exécutez ce code, alors vous serez en mesure d'obtenir une page Web du monde Bonjour à la fois http://localhost:1111/ et 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-ce que ça va avec GIL? – sashab

+1

@scrat: Le GIL n'aura pas beaucoup d'importance pour ce code, car ce code sera principalement lié aux e/s, et la plupart des E/S en Python sont écrites en utilisant des bibliothèques C de bas niveau qui libèrent le GIL. Comme pour la plupart des questions de performances, mon conseil est de ne pas vous inquiéter à ce sujet, sauf si vous avez comparé votre code et déterminé que c'est réellement un problème. –

+0

+1 pour coller à la bibliothèque standard :) –

4

pas facilement. Vous pourriez avoir deux instances de ThreadingHTTPServer, écrivez votre propre fonction serve_forever() (ne vous inquiétez pas, ce n'est pas une fonction compliquée).

La fonction existante:

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

Donc, notre remplacement serait quelque chose comme:

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

Je dirais que enfiler quelque chose ce simple est surpuissant. Il vaut mieux utiliser une forme de programmation asynchrone.

Voici un exemple en utilisant 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() 

Je pense aussi il semble beaucoup plus propre à ce que chaque port soit géré de la même manière, au lieu d'avoir le thread principal manche un port et un fil supplémentaire gérer l'autre. On peut dire que cela peut être corrigé dans l'exemple de thread, mais alors vous utilisez trois threads.

+0

Vous faites de très bons points, et j'ai été tenté de vous conseiller d'utiliser Twisted dans ma réponse. Le principal avantage de mon approche est qu'elle ne nécessite rien en dehors de la bibliothèque standard. Pour une application réelle, j'utiliserais juste CherryPy derrière Apache ou autre chose qui n'est pas BaseHTTPServer. –