كيف أكتب خادم python HTTP للاستماع على منافذ متعددة؟

StackOverflow https://stackoverflow.com/questions/60680

  •  09-06-2019
  •  | 
  •  

سؤال

أنا أكتب خادم ويب صغير في بايثون، باستخدام BaseHTTPServer وفئة فرعية مخصصة من BaseHTTPServer.BaseHTTPRequestHandler.هل من الممكن جعل هذا الاستماع على أكثر من منفذ؟

ما أفعله الآن:

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

class ThreadingHTTPServer(ThreadingMixIn, HTTPServer): 
    pass

server = ThreadingHTTPServer(('localhost', 80), MyRequestHandler)
server.serve_forever()
هل كانت مفيدة؟

المحلول

بالتأكيد؛ما عليك سوى تشغيل خادمين مختلفين على منفذين مختلفين في خيطين مختلفين يستخدم كل منهما نفس المعالج.إليك مثال عملي كامل كتبته واختبرته للتو.إذا قمت بتشغيل هذا الكود فسوف تتمكن من الحصول على صفحة ويب Hello World في كليهما 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)

تحديث:

يعمل هذا أيضًا مع Python 3 ولكن هناك ثلاثة أسطر تحتاج إلى تغيير طفيف:

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

و

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

نصائح أخرى

أود أن أقول إن الترابط لشيء بهذه البساطة هو مبالغة.من الأفضل أن تستخدم أحد أشكال البرمجة غير المتزامنة.

هنا مثال باستخدام ملتوية:

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

أعتقد أيضًا أنه يبدو أكثر نظافة بكثير أن يتم التعامل مع كل منفذ بنفس الطريقة، بدلاً من جعل الخيط الرئيسي يتعامل مع منفذ واحد وخيط إضافي يتعامل مع الآخر.يمكن القول أنه يمكن إصلاح ذلك في مثال سلسلة الرسائل، ولكن بعد ذلك تستخدم ثلاثة سلاسل رسائل.

ليس بسهولة.يمكن أن يكون لديك مثيلين لـ ThreadingHTTPServer، واكتب وظيفةserv_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()
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top