Domanda

Sto scrivendo un piccolo server web in Python, utilizzando BaseHTTPServer e una sottoclasse personalizzata di BaseHTTPServer.BaseHTTPRequestHandler.È possibile effettuare l'ascolto su più di una porta?

Cosa sto facendo adesso:

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

class ThreadingHTTPServer(ThreadingMixIn, HTTPServer): 
    pass

server = ThreadingHTTPServer(('localhost', 80), MyRequestHandler)
server.serve_forever()
È stato utile?

Soluzione

Sicuro;basta avviare due server diversi su due porte diverse in due thread diversi che utilizzano ciascuno lo stesso gestore.Ecco un esempio completo e funzionante che ho appena scritto e testato.Se esegui questo codice sarai in grado di ottenere una pagina web Hello World su entrambi http://localhost:1111/ E 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)

aggiornamento:

Funziona anche con Python 3 ma è necessario modificare leggermente tre righe:

from socketserver import ThreadingMixIn
from http.server import HTTPServer, BaseHTTPRequestHandler

E

self.wfile.write(bytes("Hello World!", "utf-8"))

Altri suggerimenti

Direi che il threading per qualcosa di così semplice è eccessivo.Faresti meglio a usare una qualche forma di programmazione asincrona.

Ecco un esempio utilizzando Contorto:

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

Penso anche che sia molto più pulito avere ciascuna porta gestita allo stesso modo, invece di avere il thread principale che gestisce una porta e un thread aggiuntivo che gestisce l'altra.Probabilmente questo può essere risolto nell'esempio del thread, ma in questo caso stai utilizzando tre thread.

Non facilmente.Potresti avere due istanze ThreadingHTTPServer, scrivere la tua funzione serve_forever() (non preoccuparti, non è una funzione complicata).

La funzione esistente:

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

Quindi la nostra sostituzione sarebbe qualcosa del tipo:

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()
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top