{"id":122,"date":"2026-08-03T16:20:30","date_gmt":"2026-08-03T08:20:30","guid":{"rendered":"https:\/\/www.cloudnote.cc\/?p=122"},"modified":"2026-08-03T16:20:30","modified_gmt":"2026-08-03T08:20:30","slug":"%e3%80%90python%e3%80%91wsgi%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90-2","status":"publish","type":"post","link":"https:\/\/www.cloudnote.cc\/index.php\/2026\/08\/03\/%e3%80%90python%e3%80%91wsgi%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90-2\/","title":{"rendered":"\u3010Python\u3011wsgi\u6e90\u7801\u89e3\u6790"},"content":{"rendered":"<h2>python\u4e2dwsgi\u6e90\u7801\u89e3\u6790<\/h2>\n<p>WSGI\uff08Web Server Gateway Interface\uff0c\u7f51\u7edc\u670d\u52a1\u5668\u7f51\u5173\u63a5\u53e3\uff09\u662f Python Web \u5f00\u53d1\u4e2d\u6700\u6838\u5fc3\u7684\u5e95\u5c42\u6807\u51c6\u4e4b\u4e00\u3002\u5b83\u4e0d\u662f\u4e00\u4e2a\u670d\u52a1\u5668\uff0c\u4e5f\u4e0d\u662f\u4e00\u4e2a\u6846\u67b6\uff0c\u66f4\u4e0d\u662f\u4e00\u6bb5\u5177\u4f53\u7684\u4ee3\u7801\uff0c\u800c\u662f\u4e00\u5957\u89c4\u8303 \/ \u6807\u51c6\uff08PEP 3333\uff09 [1]\u3002\u5b83\u5b9a\u4e49\u4e86\u201cWeb \u670d\u52a1\u5668\uff08\u5982 Nginx\/uWSGI\uff09\u201d\u4e0e\u201cPython Web \u6846\u67b6\uff08\u5982 Flask\/Django\uff09\u201d\u4e4b\u95f4\u8be5\u5982\u4f55\u8fdb\u884c\u6570\u636e\u4ea4\u4e92\u3002<\/p>\n<h3>\u4e3a\u4ec0\u4e48\u9700\u8981 WSGI\uff1f\uff08\u89e3\u51b3\u4ec0\u4e48\u75db\u70b9\uff09<\/h3>\n<p>\u5728 WSGI \u51fa\u73b0\u4e4b\u524d\uff082003\u5e74\u4ee5\u524d\uff09\uff0cPython Web \u6846\u67b6\u5c42\u51fa\u4e0d\u7a77\uff0c\u4f46\u6bcf\u4e2a\u6846\u67b6\u4e0e\u670d\u52a1\u5668\u8fde\u63a5\u7684\u65b9\u5f0f\u90fd\u5404\u4e0d\u76f8\u540c\uff08\u6709\u7684\u7528 CGI\uff0c\u6709\u7684\u7528 FastCGI\uff0c\u6709\u7684\u7528 Mod_python\uff09\u3002<\/p>\n<ul>\n<li><strong><em>\u75db\u70b9<\/em><\/strong>\uff1a\u5982\u679c\u4f60\u7528 Flask\uff08\u5047\u8bbe\u5f53\u65f6\u5b58\u5728\uff09\u5199\u4e86\u4e00\u4e2a\u7f51\u7ad9\uff0c\u914d\u7f6e\u4e86 Apache \u670d\u52a1\u5668\uff1b\u5f53\u4f60\u60f3\u6362\u6210 Nginx \u670d\u52a1\u5668\u65f6\uff0c\u4f60\u53ef\u80fd\u9700\u8981\u91cd\u5199\u6846\u67b6\u5e95\u5c42\u7684\u5bf9\u63a5\u4ee3\u7801\u3002<\/li>\n<li><strong><em>\u89e3\u51b3\u65b9\u6848<\/em><\/strong>\uff1aWSGI \u5c31\u50cf\u662f\u4e00\u4e2a\u201c\u63d2\u5934\u6807\u51c6\u201d\u3002\u670d\u52a1\u5668\u5b9e\u73b0 WSGI \u63a5\u53e3\uff0c\u6846\u67b6\u4e5f\u5b9e\u73b0 WSGI \u63a5\u53e3\u3002\u4e24\u8fb9\u53ea\u8981\u6807\u51c6\u4e00\u81f4\uff0c\u4efb\u4f55 WSGI \u670d\u52a1\u5668\u90fd\u53ef\u4ee5\u8fd0\u884c\u4efb\u4f55 WSGI \u6846\u67b6\uff0c\u5b9e\u73b0\u4e86\u771f\u6b63\u7684\u89e3\u8026\u3002<\/li>\n<\/ul>\n<h3>WSGI \u7684\u6838\u5fc3\u8fd0\u4f5c\u539f\u7406WSGI<\/h3>\n<p>\u89c4\u8303\u975e\u5e38\u7b80\u5355\uff0c\u5b83\u53ea\u8981\u6c42\u4e24\u4ef6\u4e8b\uff1a<\/p>\n<ul>\n<li><strong><em>1.\u670d\u52a1\u5668\u7aef\uff08Server\uff09<\/em><\/strong>\uff1a\u8d1f\u8d23\u63a5\u6536\u5ba2\u6237\u7aef\u7684 HTTP \u8bf7\u6c42\uff0c\u5e76\u8c03\u7528\u4e00\u4e2a\u7531\u6846\u67b6\u63d0\u4f9b\u7684\u53ef\u8c03\u7528\u5bf9\u8c61\uff08Callable\uff0c\u901a\u5e38\u662f\u4e00\u4e2a\u51fd\u6570\u6216\u7c7b\uff09\u3002<\/li>\n<li><strong><em>2.\u5e94\u7528\u7a0b\u5e8f\/\u6846\u67b6\u7aef\uff08Application\uff09<\/em><\/strong>\uff1a\u5fc5\u987b\u63d0\u4f9b\u4e00\u4e2a\u63a5\u6536\u4e24\u4e2a\u56fa\u5b9a\u53c2\u6570\u7684\u51fd\u6570\uff0c\u5904\u7406\u5b8c\u4e1a\u52a1\u540e\u5c06 HTTP \u54cd\u5e94\u8fd4\u56de\u7ed9\u670d\u52a1\u5668\u3002\n<strong><em>\u8fd9\u4e24\u4e2a\u56fa\u5b9a\u7684\u53c2\u6570\u662f\uff1a<\/em><\/strong><\/li>\n<li><strong><em>environ<\/em><\/strong>\uff1a\u4e00\u4e2a\u6807\u51c6\u7684 Python \u5b57\u5178\uff08Dict\uff09\uff0c\u91cc\u9762\u5305\u542b\u4e86\u6240\u6709\u7684 HTTP \u8bf7\u6c42\u4fe1\u606f\uff08\u5982\u8bf7\u6c42\u8def\u5f84 PATH_INFO\u3001\u8bf7\u6c42\u65b9\u6cd5 REQUEST_METHOD\u3001Header \u5934\u7b49\uff09\u3002<\/li>\n<li><strong><em>start_response<\/em><\/strong>\uff1a\u4e00\u4e2a\u7531\u670d\u52a1\u5668\u63d0\u4f9b\u7684\u56de\u8c03\u51fd\u6570\uff0c\u7528\u4e8e\u53d1\u9001 HTTP \u72b6\u6001\u7801\uff08\u5982 200 OK\uff09\u548c\u54cd\u5e94\u5934\uff08Headers\uff09\u3002<\/li>\n<\/ul>\n<h4>\u5f15\u4f8b<\/h4>\n<p>\u4f7f\u7528wsgiref\u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684web\u670d\u52a1<\/p>\n<pre><code class=\"lang-python language-python python\">from wsgiref.simple_server import make_server\nimport time\n\ndef application(environ, start_response):\n    # \u4ece environ \u5b57\u5178\u4e2d\u83b7\u53d6\u5ba2\u6237\u7aef\u8bf7\u6c42\u7684\u8def\u5f84\n    path = environ.get('PATH_INFO', '\/')\n\n    # \u4e1a\u52a1\u903b\u8f91\u5904\u7406\n    if path == '\/':\n        response_body = b&quot;Welcome to Home Page!&quot;\n        status = '200 OK'\n    elif path == '\/hello':\n        response_body = b&quot;Hello, WSGI World!&quot;\n        status = '200 OK'\n    else:\n        response_body = b&quot;404 Not Found&quot;\n        status = '404 NOT FOUND'\n\n    # \u8bbe\u7f6e\u54cd\u5e94\u5934\n    response_headers = [\n        ('Content-Type', 'text\/plain; charset=utf-8'),\n        ('Content-Length', str(len(response_body)))\n    ]\n\n    # 2. \u8c03\u7528\u670d\u52a1\u5668\u4f20\u8fdb\u6765\u7684 start_response \u56de\u8c03\uff0c\u53d1\u9001\u72b6\u6001\u7801\u548c\u8bf7\u6c42\u5934\n    start_response(status, response_headers)\n    # 3. \u5fc5\u987b\u8fd4\u56de\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08\u901a\u5e38\u662f\u5305\u542b\u5b57\u8282\u4e32\u7684\u5217\u8868\uff09\u4f5c\u4e3a Body\n    return [response_body]\n\n# 4. \u542f\u52a8\u4e00\u4e2a WSGI \u670d\u52a1\u5668\uff08Server\uff09\nif __name__ == '__main__':\n    server = make_server('127.0.0.1', 8000,application)\n    print(&quot;WSGI \u670d\u52a1\u5668\u5df2\u5728 http:\/\/127.0.0.1:8000 \u542f\u52a8...&quot;)\n    server.serve_forever()\n<\/code><\/pre>\n<h5>\u4ee3\u7801\u89e3\u6790<\/h5>\n<p>1.\u5b9a\u4e49\u4e86\u4e00\u4e2aapplication\u51fd\u6570,\u63a5\u6536environ, start_response\u4e24\u4e2a\u53d8\u91cf,\u8fd9\u4e24\u4e2a\u53d8\u91cf\u5c06\u7531 ServerHandler\u7c7b(wsgiref.simple_server\u5305\u5185\u5b9a\u4e49)\u521b\u5efa\u7684\u5bf9\u8c61\u4f20\u9012\u6570\u636e,\u4e0b\u6587\u4f1a\u89e3\u8bfb\u5230\u3002\n(1)path = environ.get(&#8216;PATH_INFO&#8217;, &#8216;\/&#8217;)\n\u4ece\u4f20\u9012\u7684environ\u5b57\u5178\u4ece\u901a\u8fc7\u5173\u952e\u5b57PATH_INFO\u83b7\u53d6,\u6ca1\u6709\u5c31\u9ed8\u8ba4&#8217;\/&#8217;\n(2)\u4e1a\u52a1\u903b\u8f91\u5904\u7406<\/p>\n<pre><code class=\"lang-python language-python python\">    if path == '\/':\n        response_body = b&quot;Welcome to Home Page!&quot;\n        status = '200 OK'\n    elif path == '\/hello':\n        response_body = b&quot;Hello, WSGI World!&quot;\n        status = '200 OK'\n    else:\n        response_body = b&quot;404 Not Found&quot;\n        status = '404 NOT FOUND'<\/code><\/pre>\n<p>\u6839\u636e\u89e3\u6790\u5230\u7684url\u8bbe\u7f6e\u4e0d\u540c\u7684\u54cd\u5e94\u4f53\u3002\n(3)\u8bbe\u7f6e\u54cd\u5e94\u5934<\/p>\n<pre><code class=\"lang-python language-python python\"> response_headers = [\n        ('Content-Type', 'text\/plain; charset=utf-8'),\n        ('Content-Length', str(len(response_body)))\n    ]<\/code><\/pre>\n<p>(4)\u8c03\u7528\u670d\u52a1\u5668\u4f20\u8fdb\u6765\u7684 start_response \u56de\u8c03\uff0c\u53d1\u9001\u72b6\u6001\u7801\u548c\u8bf7\u6c42\u5934<\/p>\n<pre><code class=\"lang-python language-python python\">start_response(status, response_headers)<\/code><\/pre>\n<p>(5)\u5fc5\u987b\u8fd4\u56de\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08\u901a\u5e38\u662f\u5305\u542b\u5b57\u8282\u4e32\u7684\u5217\u8868\uff09\u4f5c\u4e3a Body\n\u4e3a\u4f55\u9700\u8981\u8fd9\u4e2a\u8fd4\u56de\u503c?\u8fd9\u4e2a\u540e\u9762\u6e90\u7801\u91cc\u4f1a\u6709\u4f53\u73b0<\/p>\n<pre><code class=\"lang-python language-python python\">return [response_body]<\/code><\/pre>\n<p>(6)\u542f\u52a8web\u670d\u52a1<\/p>\n<pre><code class=\"lang-python language-python python\">if __name__ == '__main__':\n    server = make_server('127.0.0.1', 8000,application)\n    print(&quot;WSGI \u670d\u52a1\u5668\u5df2\u5728 http:\/\/127.0.0.1:8000 \u542f\u52a8...&quot;)\n    server.serve_forever()<\/code><\/pre>\n<p>server = make_server(&#8216;127.0.0.1&#8217;, 8000,application)<\/p>\n<blockquote>\n<p>\u8fd9\u91cc\u8c03\u7528wsgiref.simple_server\u7684make_server\u51fd\u6570\u521b\u5efa\u670d\u52a1\u542f\u52a8\u5bf9\u8c61<\/p>\n<\/blockquote>\n<p>server.serve_forever()<\/p>\n<blockquote>\n<p>\u76d1\u542c\u8bf7\u6c42\u5e76\u8c03\u7528WSGI \u5e94\u7528application(\u53ea\u6709\u6b63\u5e38\u5e76\u5141\u8bb8\u7684\u8bf7\u6c42\u540e\u8c03\u7528application\u5b8c\u6210\u6267\u884c\u6d41\u7a0b)<\/p>\n<\/blockquote>\n<h3>make_server(&#8216;127.0.0.1&#8217;, 8000,application)\u4ee3\u7801\u89e3\u6790<\/h3>\n<p>mac\u7cfb\u7edf: cmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbmake_server\u8fdb\u5165\u6e90\u7801\n\u6587\u4ef6\u4f4d\u7f6e:wsgiref\u6a21\u5757simple_server.py\u6587\u4ef6(\u7b2c150\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">def make_server(\n    host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler\n):\n    &quot;&quot;&quot;Create a new WSGI server listening on `host` and `port` for `app`&quot;&quot;&quot;\n    server = server_class((host, port), handler_class)\n    server.set_app(app)\n    return server<\/code><\/pre>\n<p>\u8fd9\u4e2a\u51fd\u6570\u901a\u8fc7WSGIServer\u7c7b,\u4f20\u9012(&#8216;127.0.0.1&#8217;, 8000)\u53caWSGIRequestHandler\u521b\u5efa\u4e00\u4e2a\u5b9e\u4f8b\u5bf9\u8c61server\u5e76\u8fd4\u56de<\/p>\n<h5>server.set_app(app)<\/h5>\n<p>mac\u7cfb\u7edf: cmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbset_app\u8fdb\u5165\u6e90\u7801\n\u4f4d\u7f6e:wsgiref\u6a21\u5757simple_server.py\u6587\u4ef6(\u7b2c66\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">class WSGIServer(HTTPServer):\n\n    &quot;&quot;&quot;BaseHTTPServer that implements the Python WSGI protocol&quot;&quot;&quot;\n\n    application = None\n    ...\n    def set_app(self,application):\n        self.application = application<\/code><\/pre>\n<p>\u6240\u91cc\u8fd9\u53e5\u4ee3\u7801\u7684\u610f\u601d\u662f\u5c06\u5b9a\u4e49\u7684WSGI \u5e94\u7528application\u8d4b\u503c\u7ed9server\u5bf9\u8c61\u7684application\u5c5e\u6027,\u8fd9\u6837server\u53ef\u4ee5\u8c03\u7528WSGI \u5e94\u7528<\/p>\n<h5>\u4e0b\u9762\u6211\u4eec\u7406\u6e05\u4e0bWSGIServer\u7c7b\u7684\u7ee7\u627f\u5173\u7cfb:<\/h5>\n<p>(1) make_server\u51fd\u6570\u9875\u9762WSGIServer\u7c7b\ncmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbWSGIServer\u8fdb\u5165\u6e90\u7801\n\u4f4d\u7f6e:wsgiref\u6a21\u5757simple_server.py\u6587\u4ef6(\u7b2c42\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">class WSGIServer(HTTPServer):\n\n    &quot;&quot;&quot;BaseHTTPServer that implements the Python WSGI protocol&quot;&quot;&quot;\n\n    application = None\n\n    def server_bind(self):\n        &quot;&quot;&quot;Override server_bind to store the server name.&quot;&quot;&quot;\n        HTTPServer.server_bind(self)\n        self.setup_environ()\n\n    def setup_environ(self):\n        # Set up base environment\n        env = self.base_environ = {}\n        env['SERVER_NAME'] = self.server_name\n        env['GATEWAY_INTERFACE'] = 'CGI\/1.1'\n        env['SERVER_PORT'] = str(self.server_port)\n        env['REMOTE_HOST']=''\n        env['CONTENT_LENGTH']=''\n        env['SCRIPT_NAME'] = ''\n\n    def get_app(self):\n        return self.application\n\n    def set_app(self,application):\n        self.application = application\n<\/code><\/pre>\n<p>\u6ca1\u6709\u5b9a\u4e49<strong>init<\/strong>\u51fd\u6570,\u6211\u4eec\u7ee7\u7eed\u5f80\u4e0a\u627e\u5b83\u7684\u7ee7\u627f\u7c7bHTTPServer\n(2)wsgiref\u6a21\u5757simple_server.py\u91ccWSGIServer\u7c7b\ncmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbHTTPServer\u7c7b\u8fdb\u5165\u6e90\u7801\n\u4f4d\u7f6e:http\u6a21\u5757server.py\u6587\u4ef6(\u7b2c130\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">class HTTPServer(socketserver.TCPServer):\n\n    allow_reuse_address = 1    # Seems to make sense in testing environment\n\n    def server_bind(self):\n        &quot;&quot;&quot;Override server_bind to store the server name.&quot;&quot;&quot;\n        socketserver.TCPServer.server_bind(self)\n        host, port = self.server_address[:2]\n        self.server_name = socket.getfqdn(host)\n        self.server_port = port\n<\/code><\/pre>\n<p>\u6ca1\u6709\u5b9a\u4e49<strong>init<\/strong>\u51fd\u6570,\u6211\u4eec\u7ee7\u7eed\u5f80\u4e0a\u627e\u5b83\u7684\u7ee7\u627f\u7c7bsocketserver.TCPServer<\/p>\n<p>(3)http\u6a21\u5757server.py\u91ccHTTPServer\u7c7b\ncmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbsocketserver.TCPServer\u7c7b\u8fdb\u5165\u6e90\u7801\n\u4f4d\u7f6e:socketserver\u6a21\u5757socketserver.py\u6587\u4ef6(\u7b2c392\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">class TCPServer(BaseServer):\n\n    &quot;&quot;&quot;Base class for various socket-based server classes.\n\n    Defaults to synchronous IP stream (i.e., TCP).\n\n    Methods for the caller:\n\n    - __init__(server_address, RequestHandlerClass, bind_and_activate=True)\n    - serve_forever(poll_interval=0.5)\n    - shutdown()\n    - handle_request()  # if you don't use serve_forever()\n    - fileno() -&gt; int   # for selector\n\n    Methods that may be overridden:\n\n    - server_bind()\n    - server_activate()\n    - get_request() -&gt; request, client_address\n    - handle_timeout()\n    - verify_request(request, client_address)\n    - process_request(request, client_address)\n    - shutdown_request(request)\n    - close_request(request)\n    - handle_error()\n\n    Methods for derived classes:\n\n    - finish_request(request, client_address)\n\n    Class variables that may be overridden by derived classes or\n    instances:\n\n    - timeout\n    - address_family\n    - socket_type\n    - request_queue_size (only for stream sockets)\n    - allow_reuse_address\n    - allow_reuse_port\n\n    Instance variables:\n\n    - server_address\n    - RequestHandlerClass\n    - socket\n\n    &quot;&quot;&quot;\n\n    address_family = socket.AF_INET\n\n    socket_type = socket.SOCK_STREAM\n\n    request_queue_size = 5\n\n    allow_reuse_address = False\n\n    allow_reuse_port = False\n\n    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):\n        &quot;&quot;&quot;Constructor.  May be extended, do not override.&quot;&quot;&quot;\n        BaseServer.__init__(self, server_address, RequestHandlerClass)\n        self.socket = socket.socket(self.address_family,\n                                    self.socket_type)\n        if bind_and_activate:\n            try:\n                self.server_bind()\n                self.server_activate()\n            except:\n                self.server_close()\n                raise\n\n    def server_bind(self):\n        &quot;&quot;&quot;Called by constructor to bind the socket.\n\n        May be overridden.\n\n        &quot;&quot;&quot;\n        if self.allow_reuse_address and hasattr(socket, &quot;SO_REUSEADDR&quot;):\n            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n        # Since Linux 6.12.9, SO_REUSEPORT is not allowed\n        # on other address families than AF_INET\/AF_INET6.\n        if (\n            self.allow_reuse_port and hasattr(socket, &quot;SO_REUSEPORT&quot;)\n            and self.address_family in (socket.AF_INET, socket.AF_INET6)\n        ):\n            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)\n        self.socket.bind(self.server_address)\n        self.server_address = self.socket.getsockname()\n\n    def server_activate(self):\n        &quot;&quot;&quot;Called by constructor to activate the server.\n\n        May be overridden.\n\n        &quot;&quot;&quot;\n        self.socket.listen(self.request_queue_size)\n\n    def server_close(self):\n        &quot;&quot;&quot;Called to clean-up the server.\n\n        May be overridden.\n\n        &quot;&quot;&quot;\n        self.socket.close()\n\n    def fileno(self):\n        &quot;&quot;&quot;Return socket file number.\n\n        Interface required by selector.\n\n        &quot;&quot;&quot;\n        return self.socket.fileno()\n\n    def get_request(self):\n        &quot;&quot;&quot;Get the request and client address from the socket.\n\n        May be overridden.\n\n        &quot;&quot;&quot;\n        return self.socket.accept()\n\n    def shutdown_request(self, request):\n        &quot;&quot;&quot;Called to shutdown and close an individual request.&quot;&quot;&quot;\n        try:\n            #explicitly shutdown.  socket.close() merely releases\n            #the socket and waits for GC to perform the actual close.\n            request.shutdown(socket.SHUT_WR)\n        except OSError:\n            pass #some platforms may raise ENOTCONN here\n        self.close_request(request)\n\n    def close_request(self, request):\n        &quot;&quot;&quot;Called to clean up an individual request.&quot;&quot;&quot;\n        request.close()<\/code><\/pre>\n<p>\u5230\u8fd9\u91cc\u6709\u521d\u59cb\u5316<strong>init<\/strong>.py\u4e86,\u540c\u65f6\u4e5f\u8c03\u7528\u4e86\u7236\u7c7bBaseServer\u7684<strong>init<\/strong>\u521d\u59cb\u5316,\u7ee7\u7eed\u5f80\u4e0a\u67e5\u770bBaseServer\u7c7b\u7684\u5b9e\u73b0<\/p>\n<p>(4)socketserver\u6a21\u5757socketserver.py\u91ccTCPServer\u7c7b\ncmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbBaseServer\u7c7b\u8fdb\u5165\u6e90\u7801\n\u4f4d\u7f6e:socketserver\u6a21\u5757socketserver.py\u6587\u4ef6(\u7b2c155\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseServer:\n\n    &quot;&quot;&quot;Base class for server classes.\n\n    Methods for the caller:\n\n    - __init__(server_address, RequestHandlerClass)\n    - serve_forever(poll_interval=0.5)\n    - shutdown()\n    - handle_request()  # if you do not use serve_forever()\n    - fileno() -&gt; int   # for selector\n\n    Methods that may be overridden:\n\n    - server_bind()\n    - server_activate()\n    - get_request() -&gt; request, client_address\n    - handle_timeout()\n    - verify_request(request, client_address)\n    - server_close()\n    - process_request(request, client_address)\n    - shutdown_request(request)\n    - close_request(request)\n    - service_actions()\n    - handle_error()\n\n    Methods for derived classes:\n\n    - finish_request(request, client_address)\n\n    Class variables that may be overridden by derived classes or\n    instances:\n\n    - timeout\n    - address_family\n    - socket_type\n    - allow_reuse_address\n    - allow_reuse_port\n\n    Instance variables:\n\n    - RequestHandlerClass\n    - socket\n\n    &quot;&quot;&quot;\n\n    timeout = None\n\n    def __init__(self, server_address, RequestHandlerClass):\n        &quot;&quot;&quot;Constructor.  May be extended, do not override.&quot;&quot;&quot;\n        self.server_address = server_address\n        self.RequestHandlerClass = RequestHandlerClass\n        self.__is_shut_down = threading.Event()\n        self.__shutdown_request = False\n\n    def server_activate(self):\n        &quot;&quot;&quot;Called by constructor to activate the server.\n\n        May be overridden.\n\n        &quot;&quot;&quot;\n        pass\n\n    def serve_forever(self, poll_interval=0.5):\n        &quot;&quot;&quot;Handle one request at a time until shutdown.\n\n        Polls for shutdown every poll_interval seconds. Ignores\n        self.timeout. If you need to do periodic tasks, do them in\n        another thread.\n        &quot;&quot;&quot;\n        self.__is_shut_down.clear()\n        try:\n            # XXX: Consider using another file descriptor or connecting to the\n            # socket to wake this up instead of polling. Polling reduces our\n            # responsiveness to a shutdown request and wastes cpu at all other\n            # times.\n            with _ServerSelector() as selector:\n                selector.register(self, selectors.EVENT_READ)\n\n                while not self.__shutdown_request:\n                    ready = selector.select(poll_interval)\n                    # bpo-35017: shutdown() called during select(), exit immediately.\n                    if self.__shutdown_request:\n                        break\n                    if ready:\n                        self._handle_request_noblock()\n\n                    self.service_actions()\n        finally:\n            self.__shutdown_request = False\n            self.__is_shut_down.set()\n\n    def shutdown(self):\n        &quot;&quot;&quot;Stops the serve_forever loop.\n\n        Blocks until the loop has finished. This must be called while\n        serve_forever() is running in another thread, or it will\n        deadlock.\n        &quot;&quot;&quot;\n        self.__shutdown_request = True\n        self.__is_shut_down.wait()\n\n    def service_actions(self):\n        &quot;&quot;&quot;Called by the serve_forever() loop.\n\n        May be overridden by a subclass \/ Mixin to implement any code that\n        needs to be run during the loop.\n        &quot;&quot;&quot;\n        pass\n\n    # The distinction between handling, getting, processing and finishing a\n    # request is fairly arbitrary.  Remember:\n    #\n    # - handle_request() is the top-level call.  It calls selector.select(),\n    #   get_request(), verify_request() and process_request()\n    # - get_request() is different for stream or datagram sockets\n    # - process_request() is the place that may fork a new process or create a\n    #   new thread to finish the request\n    # - finish_request() instantiates the request handler class; this\n    #   constructor will handle the request all by itself\n\n    def handle_request(self):\n        &quot;&quot;&quot;Handle one request, possibly blocking.\n\n        Respects self.timeout.\n        &quot;&quot;&quot;\n        # Support people who used socket.settimeout() to escape\n        # handle_request before self.timeout was available.\n        timeout = self.socket.gettimeout()\n        if timeout is None:\n            timeout = self.timeout\n        elif self.timeout is not None:\n            timeout = min(timeout, self.timeout)\n        if timeout is not None:\n            deadline = time() + timeout\n\n        # Wait until a request arrives or the timeout expires - the loop is\n        # necessary to accommodate early wakeups due to EINTR.\n        with _ServerSelector() as selector:\n            selector.register(self, selectors.EVENT_READ)\n\n            while True:\n                if selector.select(timeout):\n                    return self._handle_request_noblock()\n                else:\n                    if timeout is not None:\n                        timeout = deadline - time()\n                        if timeout &lt; 0:\n                            return self.handle_timeout()\n\n    def _handle_request_noblock(self):\n        &quot;&quot;&quot;Handle one request, without blocking.\n\n        I assume that selector.select() has returned that the socket is\n        readable before this function was called, so there should be no risk of\n        blocking in get_request().\n        &quot;&quot;&quot;\n        try:\n            request, client_address = self.get_request()\n        except OSError:\n            return\n        if self.verify_request(request, client_address):\n            try:\n                self.process_request(request, client_address)\n            except Exception:\n                self.handle_error(request, client_address)\n                self.shutdown_request(request)\n            except:\n                self.shutdown_request(request)\n                raise\n        else:\n            self.shutdown_request(request)\n\n    def handle_timeout(self):\n        &quot;&quot;&quot;Called if no new request arrives within self.timeout.\n\n        Overridden by ForkingMixIn.\n        &quot;&quot;&quot;\n        pass\n\n    def verify_request(self, request, client_address):\n        &quot;&quot;&quot;Verify the request.  May be overridden.\n\n        Return True if we should proceed with this request.\n\n        &quot;&quot;&quot;\n        return True\n\n    def process_request(self, request, client_address):\n        &quot;&quot;&quot;Call finish_request.\n\n        Overridden by ForkingMixIn and ThreadingMixIn.\n\n        &quot;&quot;&quot;\n        self.finish_request(request, client_address)\n        self.shutdown_request(request)\n\n    def server_close(self):\n        &quot;&quot;&quot;Called to clean-up the server.\n\n        May be overridden.\n\n        &quot;&quot;&quot;\n        pass\n\n    def finish_request(self, request, client_address):\n        &quot;&quot;&quot;Finish one request by instantiating RequestHandlerClass.&quot;&quot;&quot;\n        self.RequestHandlerClass(request, client_address, self)\n\n    def shutdown_request(self, request):\n        &quot;&quot;&quot;Called to shutdown and close an individual request.&quot;&quot;&quot;\n        self.close_request(request)\n\n    def close_request(self, request):\n        &quot;&quot;&quot;Called to clean up an individual request.&quot;&quot;&quot;\n        pass\n\n    def handle_error(self, request, client_address):\n        &quot;&quot;&quot;Handle an error gracefully.  May be overridden.\n\n        The default is to print a traceback and continue.\n\n        &quot;&quot;&quot;\n        print('-'*40, file=sys.stderr)\n        print('Exception occurred during processing of request from',\n            client_address, file=sys.stderr)\n        import traceback\n        traceback.print_exc()\n        print('-'*40, file=sys.stderr)\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, *args):\n        self.server_close()\n<\/code><\/pre>\n<p>\u5230\u8fd9\u91cc\u6211\u4eec\u7406\u6e05\u4e86\u7c7b\u7ee7\u627f\u5173\u7cfb\nWSGIServer-&gt;HTTPServer-&gt;socketserver.TCPServer-&gt;BaseServer\n\u6700\u7ec8server\u5bf9\u8c61\u7531BaseServer\u7c7b\u521b\u5efa\u7684,\u6211\u4eec\u6765\u770bBaseServer\u521d\u59cb\u5316\u4ee3\u7801<\/p>\n<pre><code class=\"lang-python language-python python\">    def __init__(self, server_address, RequestHandlerClass):\n        &quot;&quot;&quot;Constructor.  May be extended, do not override.&quot;&quot;&quot;\n        self.server_address = server_address\n        self.RequestHandlerClass = RequestHandlerClass\n        self.__is_shut_down = threading.Event()\n        self.__shutdown_request = False<\/code><\/pre>\n<p>\u6839\u636e\u4f20\u9012\u7684\u53c2\u6570\u521d\u59cb\u5316\u5bf9\u8c61\u7684\u56db\u4e2a\u5c5e\u6027<\/p>\n<ul>\n<li>server_address(\u670d\u52a1\u5668\u76d1\u542c\u5730\u5740):\n<ul>\n<li>\u7c7b\u578b\uff1a\u901a\u5e38\u662f\u4e00\u4e2a\u5143\u7ec4 (str, int)\uff0c\u4f8b\u5982 (&#8216;127.0.0.1&#8217;, 8000)\u3002<\/li>\n<li>\u7269\u7406\u542b\u4e49\uff1a\u7f51\u7edc\u5957\u63a5\u5b57\uff08Socket\uff09\u7ed1\u5b9a\u7684\u7269\u7406\u5730\u5740\u548c\u7aef\u53e3 [INDEX]\u3002<\/li>\n<li>\u5e95\u5c42\u4f5c\u7528\uff1a\u540e\u7eed\u7684\u5b50\u7c7b\uff08\u5982 TCPServer\uff09\u5728\u6267\u884c\u64cd\u4f5c\u7cfb\u7edf\u7684 bind() \u7cfb\u7edf\u8c03\u7528\u65f6\uff0c\u4f1a\u76f4\u63a5\u8bfb\u53d6\u8fd9\u4e2a\u5c5e\u6027\uff0c\u544a\u8bc9\u7f51\u5361\uff1a\u201c\u4ece\u73b0\u5728\u5f00\u59cb\uff0c\u6240\u6709\u53d1\u9001\u5230 127.0.0.1 \u4e14\u76ee\u6807\u7aef\u53e3\u662f 8000 \u7684\u7f51\u7edc\u7f51\u7edc\u6570\u636e\u5305\uff0c\u5168\u5f52\u6211\u7ba1\u201d<\/li>\n<\/ul><\/li>\n<li>RequestHandlerClass(\u8bf7\u6c42\u5904\u7406\u5668\u7c7b):\n<ul>\n<li>\u7c7b\u578b\uff1a\u4e00\u4e2a\u7c7b\u5bf9\u8c61\uff08Class\uff09\u672c\u8eab\uff08\u5982 WSGIRequestHandler\uff09\uff0c\u6ce8\u610f\u4e0d\u662f\u5b9e\u4f8b\u5bf9\u8c61\u3002<\/li>\n<li>\u7269\u7406\u542b\u4e49\uff1a\u4e1a\u52a1\u6d41\u6c34\u7ebf\u5de5\u4eba\u7684\u201c\u56fe\u7eb8\u201d\u6216\u201c\u6a21\u5177\u201d\u3002<\/li>\n<li>\u5e95\u5c42\u4f5c\u7528\uff1a\u8fd9\u5c31\u662f\u6211\u4eec\u4e4b\u524d\u770b\u5230\u7684\uff0c\u5f53 select() \u62cd\u9192\u4e3b\u7ebf\u7a0b\u5e76\u6210\u529f\u521b\u5efa\u4e13\u5c5e Socket\uff08request\uff09\u540e\uff0c\u7236\u7c7b\u4f1a\u6267\u884c self.RequestHandlerClass(request, client_address, self) [INDEX]\u3002\u670d\u52a1\u5668\u5c31\u662f\u901a\u8fc7\u8fd9\u4e2a\u5c5e\u6027\uff0c\u5728\u6bcf\u4e00\u6b21\u65b0\u8bf7\u6c42\u8fde\u5165\u65f6\uff0c\u52a8\u6001\u5b9e\u4f8b\u5316\u4e00\u4e2a\u5168\u65b0\u7684\u5de5\u4eba\u53bb\u89e3\u6790 HTTP \u534f\u8bae\u548c\u8c03\u7528\u4f60\u7684 application\u3002<\/li>\n<\/ul><\/li>\n<li>__is_shut_down(\u540c\u6b65\u72b6\u6001\u7ea2\u7eff\u706f):\n<ul>\n<li>\u3002\u7c7b\u578b\uff1athreading.Event() \u7ebf\u7a0b\u540c\u6b65\u5bf9\u8c61\u3002<\/li>\n<li>\u7269\u7406\u542b\u4e49\uff1a\u9762\u5411\u591a\u7ebf\u7a0b\u73af\u5883\u7684\u3001\u6807\u8bc6\u670d\u52a1\u5668\u662f\u5426\u201c\u5f7b\u5e95\u5bff\u7ec8\u6b63\u5bdd\u201d\u7684\u5168\u5c40\u7269\u7406\u7ea2\u7eff\u706f\u3002<\/li>\n<li>\u5e95\u5c42\u4f5c\u7528\uff1a\u5728 serve_forever() \u521a\u521a\u542f\u52a8\u65f6\uff0c\u4f1a\u7acb\u523b\u6267\u884c self.__is_shut_down.clear()\uff08\u4eae\u8d77\u7ea2\u706f\uff09\uff0c\u4ee3\u8868\u670d\u52a1\u5668\u6b63\u5728\u8fd0\u8f6c \u3002\u5f53\u7528\u6237\u5728\u53e6\u4e00\u4e2a\u7ba1\u7406\u7ebf\u7a0b\u8c03\u7528\u4e86 shutdown()\uff0c\u5e76\u4e14 serve_forever \u5f7b\u5e95\u5b89\u5168\u5730\u9000\u51fa\u4e86\u6574\u4e2a while \u5faa\u73af\u3001\u5173\u95ed\u4e86\u9009\u62e9\u5668\u540e\uff0c\u4f1a\u5728 finally \u4ee3\u7801\u5757\u91cc\u6267\u884c self.<strong>is_shut_down.set()\uff08\u4eae\u8d77\u7eff\u706f\uff09 \u3002\u5916\u90e8\u7684 shutdown() \u7ebf\u7a0b\u53ea\u8981\u5361\u5728 self.<\/strong>is_shut_down.wait() \u5904\uff0c\u5c31\u80fd\u7edd\u5bf9\u5b89\u5168\u5730\u7b49\u5230\u670d\u52a1\u5668\u5f7b\u5e95\u6e05\u7406\u5b8c\u8d44\u6e90\u540e\u518d\u9000\u51fa\uff0c\u9632\u6b62\u5185\u5b58\u6cc4\u6f0f\u3002<\/li>\n<\/ul><\/li>\n<li>__shutdown_request(\u5173\u95ed\u7533\u8bf7\u6807\u5fd7):\n<ul>\n<li>\u7c7b\u578b\uff1a\u5e03\u5c14\u503c\uff08False \u6216 True\uff09\u3002<\/li>\n<li>\u7269\u7406\u542b\u4e49\uff1a\u4e8b\u4ef6\u5faa\u73af\u662f\u5426\u5e94\u8be5\u7d27\u6025\u9000\u51fa\u7684\u63a7\u5236\u5f00\u5173\uff08\u5e03\u5c14\u65d7\u5e1c\uff09 \u3002<\/li>\n<li>\u5e95\u5c42\u4f5c\u7528\uff1a\u521d\u59cb\u72b6\u6001\u4e3a False\uff0c\u6240\u4ee5 serve_forever \u7684 while not self.<strong>shutdown_request: \u80fd\u591f\u4e00\u76f4\u6210\u7acb\uff0c\u8ba9\u4e8b\u4ef6\u5faa\u73af\u75af\u72c2\u8fd0\u8f6c \u3002\u5f53\u4f60\u5728\u522b\u7684\u7ebf\u7a0b\u8c03\u7528 server.shutdown() \u65f6\uff0c\u5e95\u5c42\u5176\u5b9e\u53ea\u5e72\u4e86\u4e00\u4ef6\u4e8b\uff1a\u628a\u8fd9\u4e2a\u65d7\u5e1c\u5f3a\u884c\u6539\u4e3a True\u3002serve_forever \u91cc\u7684 selector.select() \u9192\u6765\u540e\uff0c\u4e00\u65e6\u649e\u5230 if self.<\/strong>shutdown_request: break\uff0c\u5c31\u4f1a\u77ac\u95f4\u5411\u4e0b\u4e00\u5c42\u6e83\u8d25\u5e76\u5b89\u5168\u9000\u51fa\u6574\u4e2a\u7a0b\u5e8f\u3002<\/li>\n<\/ul><\/li>\n<\/ul>\n<p><span style=\"color:red\">\u5f53\u7136\u9664\u4e86\u8fd94\u4e2a\u5bf9\u8c61\u5c5e\u6027,server\u5b9e\u4f8b\u8fd8\u5305\u62ec\u5404\u7ea7\u7ee7\u627f\u7c7b\u7684\u7c7b\u5c5e\u6027\u4e5f\u4f1a\u521d\u59cb\u5316,\u5177\u4f53\u5176\u4ed6\u7c7b\u5c5e\u6027\u5728\u4e0a\u9762\u4ee3\u7801\u6709\u5c55\u793a,\u53e6\u5916\u5b9e\u4f8b\u7edd\u5bf9\u53ef\u4ee5\u968f\u65f6\u968f\u5730\u8c03\u7528\u7c7b\u5c5e\u6027\uff0c\u53ea\u4e0d\u8fc7\u5f53\u5b9e\u4f8b\u81ea\u5df1\u7684\u53e3\u888b\u91cc\u6709\u540c\u540d\u5c5e\u6027\u65f6\uff0c\u4f1a\u4f18\u5148\u7528\u81ea\u5df1\u7684<\/span><\/p>\n<h3>server.serve_forever()\u4ee3\u7801\u89e3\u6790<\/h3>\n<p>\u5728\u4e3b\u4ee3\u7801\u5c42:cmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbserve_forever\u8fdb\u5165\u6e90\u7801\n\u4f4d\u7f6e:socketserver\u6a21\u5757socketserver.py\u6587\u4ef6(\u7b2c218\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseServer:\n       ...\n       def serve_forever(self, poll_interval=0.5):\n        &quot;&quot;&quot;Handle one request at a time until shutdown.\n\n        Polls for shutdown every poll_interval seconds. Ignores\n        self.timeout. If you need to do periodic tasks, do them in\n        another thread.\n        &quot;&quot;&quot;\n        self.__is_shut_down.clear()\n        try:\n            # XXX: Consider using another file descriptor or connecting to the\n            # socket to wake this up instead of polling. Polling reduces our\n            # responsiveness to a shutdown request and wastes cpu at all other\n            # times.\n            with _ServerSelector() as selector:\n                selector.register(self, selectors.EVENT_READ)\n\n                while not self.__shutdown_request:\n                    ready = selector.select(poll_interval)\n                    # bpo-35017: shutdown() called during select(), exit immediately.\n                    if self.__shutdown_request:\n                        break\n                    if ready:\n                        self._handle_request_noblock()\n\n                    self.service_actions()\n        finally:\n            self.__shutdown_request = False\n            self.__is_shut_down.set()\n<\/code><\/pre>\n<p>serve_forever\u51fd\u6570\u5728BaseServer\u7c7b\u4e0b\u5b9a\u4e49,\u63a5\u4e0b\u6765\u89e3\u6790serve_forever<\/p>\n<p><strong><em>(1)\u9996\u5148\u8c03\u7528\u4e86\u5bf9\u8c61\u7684self.__is_shut_down.clear()<\/em><\/strong>\n\u8fd9\u4e2a\u5176\u5b9e\u5c31\u662f\u5c06\u5185\u90e8\u7684 Flag \u72b6\u6001\u91cd\u7f6e\u4e3a False\uff08\u4e5f\u5c31\u662f\u4eae\u8d77\u7ea2\u706f\uff09\uff0c\u4ece\u800c\u8ba9\u540e\u7eed\u6240\u6709\u6267\u884c\u5230 wait() \u7684\u7ebf\u7a0b\u5168\u90e8\u5361\u4f4f\uff0c\u8fdb\u5165\u4f11\u7720\u7b49\u5f85\u72b6\u6001\u3002<\/p>\n<p>\ud83c\udf1f \u4e3a\u4ec0\u4e48\u8981\u5728\u7b2c\u4e00\u6b65\u6267\u884c clear()\uff1f<\/p>\n<ul>\n<li>\u56e0\u4e3a\u8fd9\u4e2a\u670d\u52a1\u5668\u5b9e\u4f8b\u5728\u5b9e\u9645\u8fd0\u884c\u4e2d\uff0c\u53ef\u80fd\u4f1a\u88ab\u591a\u6b21\u5173\u95ed\u3001\u53c8\u591a\u6b21\u91cd\u542f\uff08\u6bd4\u5982\u5728\u81ea\u52a8\u5316\u5355\u5143\u6d4b\u8bd5\u4e2d\uff09\u3002<\/li>\n<li>\u6bcf\u6b21\u91cd\u542f\u8fdb\u5165\u4e8b\u4ef6\u5faa\u73af\u65f6\uff0c\u5fc5\u987b\u624b\u52a8\u628a\u201c\u662f\u5426\u5df2\u5173\u95ed\u201d\u7684\u7eff\u706f\u5207\u56de\u7ea2\u706f\uff08False\uff09\uff0c<\/li>\n<li>\u5426\u5219\u5916\u90e8\u7684 shutdown() \u5c31\u4f1a\u4ea7\u751f\u8bef\u5224\uff0c\u8bef\u4ee5\u4e3a\u670d\u52a1\u5668\u5df2\u7ecf\u5173\u95ed\u4e86\u3002<\/li>\n<\/ul>\n<p><strong><em>(2)ServerSelector<\/em><\/strong>\n\u8fd9\u4e2a\u5728\u6587\u4ef6\u7684\u5934\u90e8\u6709\u5b9a\u4e49<\/p>\n<pre><code class=\"lang-python language-python python\">import selectors\n...\n# 1. \u68c0\u67e5\u5f53\u524d\u64cd\u4f5c\u7cfb\u7edf\u7684 selectors \u6a21\u5757\u4e2d\u662f\u5426\u5305\u542b 'PollSelector' \u8fd9\u4e2a\u7c7b\nif hasattr(selectors, 'PollSelector'):\n    # \u5982\u679c\u6709\uff08\u5e38\u89c1\u4e8e Linux\u3001Unix \u6216 macOS \u751f\u4ea7\u73af\u5883\uff09\uff0c\u5c31\u91c7\u7528\u6027\u80fd\u66f4\u597d\u7684 PollSelector\n    _ServerSelector = selectors.PollSelector\nelse:\n    # \u5982\u679c\u6ca1\u6709\uff08\u5e38\u89c1\u4e8e\u6807\u51c6\u7684 Windows \u5f00\u53d1\u73af\u5883\uff09\uff0c\u5c31\u964d\u7ea7\u91c7\u7528\u517c\u5bb9\u6027\u6700\u5f3a\u7684 SelectSelector\n    _ServerSelector = selectors.SelectSelector\n...<\/code><\/pre>\n<p>\u8fd9\u6bb5\u5b9a\u4e49\u4f5c\u7528\uff1a\u6839\u636e\u7a0b\u5e8f\u5f53\u524d\u8fd0\u884c\u7684\u64cd\u4f5c\u7cfb\u7edf\uff08OS\uff09\u73af\u5883\uff0c\u81ea\u52a8\u9009\u62e9\u6027\u80fd\u6700\u597d\u7684 I\/O \u591a\u8def\u590d\u7528\uff08I\/O Multiplexing\uff09\u673a\u5236\uff0c\u5e76\u7ed9\u5b83\u8d77\u4e00\u4e2a\u7edf\u4e00\u7684\u540d\u5b57\u53eb\u505a _ServerSelector\u3002<\/p>\n<pre><code class=\"lang-python language-python python\"># \u7528 with \u8bed\u53e5\u786e\u4fdd\u7528\u5b8c\u540e\u81ea\u52a8\u5173\u95ed\u3001\u91ca\u653e\u64cd\u4f5c\u7cfb\u7edf\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26\u8d44\u6e90\nwith _ServerSelector() as selector:\n    #\u3010\u6838\u5fc3\u6b65\u9aa4\u3011\u5c06\u670d\u52a1\u5668\u81ea\u8eab\uff08self\uff0c\u5176\u5b9e\u5c31\u662f\u76d1\u542c\u7f51\u7edc\u7aef\u53e3\u7684\u76d1\u542c\u5957\u63a5\u5b57 Listening Socket\uff09\u6ce8\u518c\u5230\u76d1\u63a7\u5668\u4e2d\n    # \u544a\u8bc9\u64cd\u4f5c\u7cfb\u7edf\uff1a&ldquo;\u53ea\u8981\u6709\u5ba2\u6237\u7aef\u5411\u8fd9\u4e2a\u7aef\u53e3\u53d1\u9001\u8fde\u63a5\u8bf7\u6c42\uff0c\u5c31\u89e6\u53d1&lsquo;\u53ef\u8bfb\u4e8b\u4ef6&rsquo;\uff08EVENT_READ\uff09&rdquo;\n    selector.register(self, selectors.EVENT_READ)\n\n    #\u53ea\u8981\u670d\u52a1\u5668\u6ca1\u6709\u6536\u5230\u5173\u95ed\u4fe1\u53f7\uff08__shutdown_request \u4e3a False\uff09\uff0c\u5c31\u8fdb\u5165\u65e0\u9650\u5faa\u73af\u6301\u7eed\u5de5\u4f5c\n    while not self.__shutdown_request:\n        #\u3010\u6700\u5173\u952e\u7684\u5e95\u5c42\u4f11\u7720\u3011\u8ba9\u5f53\u524d\u7ebf\u7a0b\u8fdb\u5165\u963b\u585e\uff08\u4f11\u7720\uff09\u72b6\u6001\uff0c\u628a\u76ef\u7740\u7aef\u53e3\u7684\u6d3b\u513f\u5f7b\u5e95\u629b\u7ed9\u64cd\u4f5c\u7cfb\u7edf\u5185\u6838\n        # \u8bbe\u7f6e\u4e00\u4e2a\u6700\u5927\u7b49\u5f85\u65f6\u95f4\uff08poll_interval \u79d2\uff0c\u9ed8\u8ba4 0.5 \u79d2\uff09\u3002\u5728\u8fd9\u671f\u95f4\uff0c\u5982\u679c\u6ca1\u6709\u8bf7\u6c42\uff0cCPU \u4f7f\u7528\u7387\u4e3a 0%\uff01\n        ready = selector.select(poll_interval)\n        # bpo-35017: shutdown() called during select(), exit immediately.\n        # \u5982\u679c\u5728\u7b2c 4 \u6b65\u4f11\u7720\u671f\u95f4\uff0c\u5916\u90e8\u7684\u7ba1\u7406\u7ebf\u7a0b\u8c03\u7528\u4e86 shutdown() \u8bd5\u56fe\u5173\u95ed\u670d\u52a1\u5668\uff0c\n        # \u5f53\u7ebf\u7a0b\u88ab\u5524\u9192\u540e\uff0c\u7acb\u523b\u8fdb\u884c\u4e8c\u6b21\u68c0\u67e5\uff0c\u5982\u679c\u786e\u5b9e\u8981\u5173\u95ed\uff0c\u76f4\u63a5 break \u9000\u51fa\u5faa\u73af\uff0c\u9632\u6b62\u7a0b\u5e8f\u5361\u6b7b\u6216\u591a\u8dd1\u4e00\u5708\n        if self.__shutdown_request:\n            break\n        # \u5982\u679c ready \u5217\u8868\u4e0d\u4e3a\u7a7a\uff0c\u610f\u5473\u7740\u64cd\u4f5c\u7cfb\u7edf\u901a\u77e5\u6211\u4eec\uff1a&ldquo;\u6709\u5ba2\u6237\u7aef\u8fde\u8fdb\u6765\u4e86\uff01&rdquo;\n        if ready:\n            # \u91c7\u7528\u975e\u963b\u585e\uff08noblock\uff09\u7684\u65b9\u5f0f\uff0c\u5b89\u5168\u5730\u63a5\u6536\u8fd9\u4e2a\u8fde\u63a5\uff0c\u5e76\u628a\u6570\u636e\u4e22\u7ed9\u5177\u4f53\u7684\u4e1a\u52a1\u903b\u8f91\u53bb\u5904\u7406\n            self._handle_request_noblock()\n        # \u65e0\u8bba\u6709\u6ca1\u6709\u6536\u5230\u8bf7\u6c42\uff0c\u6bcf\u4e00\u8f6e\u5faa\u73af\u7ed3\u675f\u65f6\uff0c\u90fd\u4f1a\u6267\u884c\u4e00\u4e9b\u670d\u52a1\u5668\u7684\u5b9a\u65f6\u7ef4\u62a4\u52a8\u4f5c\uff08\u5982\u6e05\u7406\u8fc7\u671f\u7684\u6b7b\u94fe\u63a5\u7b49\uff09\n        self.service_actions()<\/code><\/pre>\n<p><strong><em>(3)finally<\/em><\/strong><\/p>\n<pre><code class=\"lang-python language-python python\">finally:\n    self.__shutdown_request = False\n    self.__is_shut_down.set()<\/code><\/pre>\n<p>\u5728 Python \u4e2d\uff0cfinally \u5757\u91cc\u7684\u4ee3\u7801\u62e5\u6709\u7edd\u5bf9\u7684\u6267\u884c\u7279\u6743\uff1a\u65e0\u8bba\u524d\u9762\u7684 try \u5757\u91cc\u662f\u6b63\u5e38\u8fd0\u884c\u7ed3\u675f\u3001\u6267\u884c\u4e86 break \u9000\u51fa\u3001\u8fd8\u662f\u53d1\u751f\u4e86\u4e25\u91cd\u7684\u5d29\u6e83\u5f02\u5e38\uff0cfinally \u5185\u90e8\u7684\u4ee3\u7801\u767e\u5206\u4e4b\u767e\u4f1a\u88ab\u5f3a\u5236\u6267\u884c\u3002<\/p>\n<p>\u6240\u4ee5\u5f53\u6b63\u5e38\u8bf7\u6c42\u5230\u6765\u65f6,\u5e95\u5c42\u4f1a\u6267\u884cself._handle_request_noblock()\u8fd9\u6bb5,\u6211\u4eec\u627e\u5230\u8fd9\u6bb5\u51fd\u6570\u4ee3\u7801:<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseServer:\n   ...\n\n    def _handle_request_noblock(self):\n        &quot;&quot;&quot;Handle one request, without blocking.\n\n        I assume that selector.select() has returned that the socket is\n        readable before this function was called, so there should be no risk of\n        blocking in get_request().\n        &quot;&quot;&quot;\n        try:\n            request, client_address = self.get_request()\n        except OSError:\n            return\n        if self.verify_request(request, client_address):\n            try:\n                self.process_request(request, client_address)\n            except Exception:\n                self.handle_error(request, client_address)\n                self.shutdown_request(request)\n            except:\n                self.shutdown_request(request)\n                raise\n        else:\n            self.shutdown_request(request)<\/code><\/pre>\n<p>\u4e5f\u662f\u5b9a\u4e49\u5728BaseServer\u7c7b\u4e2d\n<strong><em>(1)\u83b7\u53d6\u8bf7\u6c42\u53ca\u5ba2\u6237\u7aef\u5730\u5740<\/em><\/strong>\nrequest, client_address = self.get_request()\n\u6211\u4eec\u518d\u627e\u5230self.get_request()\u5bf9\u5e94\u4ee3\u7801<\/p>\n<pre><code class=\"lang-python language-python python\">class TCPServer(BaseServer):\n    ...\n    def get_request(self):\n        &quot;&quot;&quot;Get the request and client address from the socket.\n\n        May be overridden.\n\n        &quot;&quot;&quot;\n        return self.socket.accept()<\/code><\/pre>\n<p>get_request\u6ca1\u7528\u5b9a\u4e49\u5728\u57fa\u7c7b\u4e2d,\u800c\u662f\u5b9a\u4e49\u5728\u7b2c\u4e8c\u7ee7\u627fTCPServer\u7c7b\u4e2d,\u800cself\u4ee3\u8868\u6700\u7ec8\u7684WSGIServer\u7c7b\u5bf9\u8c61,\u6240\u4ee5\u80fd\u8c03\u7528\u5230,\u53e6\u5916TCPServer\u7c7b\u4e2d\u6709socket\u7684\u521d\u59cb\u5316<\/p>\n<pre><code class=\"lang-python language-python python\">class TCPServer(BaseServer):\n    ...\n\n    address_family = socket.AF_INET\n\n    socket_type = socket.SOCK_STREAM\n\n    request_queue_size = 5\n\n    allow_reuse_address = False\n\n    allow_reuse_port = False\n\n    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):\n        &quot;&quot;&quot;Constructor.  May be extended, do not override.&quot;&quot;&quot;\n        BaseServer.__init__(self, server_address, RequestHandlerClass)\n        self.socket = socket.socket(self.address_family,\n                                    self.socket_type)<\/code><\/pre>\n<p>\u6240\u4ee5get_request\u8fd4\u56de\u7684\u662f:socket.socket(socket.AF_INET,\nsocket.SOCK_STREAM).accept()<\/p>\n<p><strong><em>(2)\u6821\u9a8c\u8bf7\u6c42<\/em><\/strong>\n\u901a\u8fc7self.verify_request(request, client_address)\u6821\u9a8c\u8bf7\u6c42,\u6839\u636e\u7ee7\u627f\u5173\u7cfb\u67e5\u627e,verify_request\u53ea\u5728BaseServer\u7c7b\u6709\u5b9a\u4e49\u4e14\u6c38\u4e45True\u3002<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseServer:\n    ...\n    def verify_request(self, request, client_address):\n        &quot;&quot;&quot;Verify the request.  May be overridden.\n\n        Return True if we should proceed with this request.\n\n        &quot;&quot;&quot;\n        return True\n<\/code><\/pre>\n<p><strong><em>(3)\u8c03\u7528process_request<\/em><\/strong>\n\u901a\u8fc7\u4e0a\u9762\u5206\u6790,\u8bf7\u6c42\u5982\u679c\u6b63\u5e38\u4f1a\u8c03\u7528self.process_request(request, client_address)\n\u6839\u636e\u7ee7\u627f\u5173\u7cfb\u67e5\u627e,process_request\u5728BaseServer\u7c7b\u4e2d\u6709\u5b9a\u4e49<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseServer:\n    ...\n    def process_request(self, request, client_address):\n        &quot;&quot;&quot;Call finish_request.\n\n        Overridden by ForkingMixIn and ThreadingMixIn.\n\n        &quot;&quot;&quot;\n        self.finish_request(request, client_address)\n        self.shutdown_request(request)<\/code><\/pre>\n<p>\u5728process_request\u4e2d\u8c03\u7528finish_request\u51fd\u6570,\u6839\u636e\u7ee7\u627f\u5173\u7cfb\u67e5\u627e,finish_request\u5728BaseServer\u7c7b\u4e2d\u6709\u5b9a\u4e49<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseServer:\n    ...\n    def finish_request(self, request, client_address):\n        &quot;&quot;&quot;Finish one request by instantiating RequestHandlerClass.&quot;&quot;&quot;\n        self.RequestHandlerClass(request, client_address, self)<\/code><\/pre>\n<p>\u5728finish_request\u4e2d\u8c03\u7528self.RequestHandlerClass,\u8fd9\u4e2a\u5176\u5b9e\u5c31\u662fmake_server\u4e2d\u4f20\u9012\u7684WSGIRequestHandler\u7c7b\u3002\n3\u4e2a\u53c2\u6570\u6765\u6e90:<\/p>\n<ul>\n<li>request, client_address\nrequest, client_address = self.get_request()\u3010socket.socket(socket.AF_INET,socket.SOCK_STREAM).accept()\u3011<\/li>\n<li>self:\n\u521b\u5efa\u7684server\u5bf9\u8c61\u81ea\u5df1\u672c\u8eab,\u8fd9\u4e2a\u6709\u521d\u59cb\u5316application\u5e94\u7528,\u521b\u5efaserver\u5bf9\u8c61\u65f6\u5df2\u901a\u8fc7server.set_app(app)\u6ce8\u518c\u8fdb\u53bb\u4e86<\/li>\n<\/ul>\n<pre><code class=\"lang-python language-python python\">def make_server(\n    host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler\n):\n    &quot;&quot;&quot;Create a new WSGI server listening on `host` and `port` for `app`&quot;&quot;&quot;\n   server = server_class((host, port), handler_class)\n    server.set_app(app)\n    return server<\/code><\/pre>\n<p>\u901a\u8fc7\u4e0a\u9762\u5206\u6790,server.serve_forever()\u5176\u5b9e\u8c03\u7528\u7684\u5c31\u662f\nWSGIRequestHandler(request, client_address, self)<\/p>\n<ul>\n<li><strong><em>request, client_address<\/em><\/strong>:\nsocket.socket(socket.AF_INET,socket.SOCK_STREAM).accept()\u89e3\u6790\u51fa\u6765<\/li>\n<li><strong><em>self<\/em><\/strong>:\nself\u5c31\u662fserver\u5bf9\u8c61\u672c\u8eab\nserver = server_class((host, port), handler_class)<\/li>\n<\/ul>\n<p>\u63a5\u4e0b\u6765\u5c31\u662f\u5206\u6790WSGIRequestHandler\u7c7b\u521d\u59cb\u5316\u8fc7\u7a0b,web\u670d\u52a1\u542f\u52a8\u5c31\u5728WSGIRequestHandler(request, client_address, self)\u521d\u59cb\u5316\u4e2d\u3002<\/p>\n<hr \/>\n<h3>WSGIRequestHandler\u521d\u59cb\u5316\u8fc7\u7a0b<\/h3>\n<p>\u57fa\u4e8e\u4e0a\u8ff0\u5206\u6790,\u670d\u52a1\u542f\u52a8\u53caapplication\u8c03\u7528\u90fd\u5728WSGIRequestHandler(request, client_address, self)\u91cc\n\u8fd8\u662f\u4ecemake_server\u51fd\u6570\u5f00\u59cb(wsgiref\u6a21\u5757simple_server.py\u6587\u4ef6\u7b2c150\u884c)<\/p>\n<pre><code>def make_server(\n    host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler\n):\n    &quot;&quot;&quot;Create a new WSGI server listening on `host` and `port` for `app`&quot;&quot;&quot;\n    server = server_class((host, port), handler_class)\n    server.set_app(app)\n    return server<\/code><\/pre>\n<h5>\u4e0b\u9762\u6211\u4eec\u7406\u6e05\u4e0bWSGIRequestHandler\u7684\u7ee7\u627f\u5173\u7cfb:<\/h5>\n<p>(1) make_server\u51fd\u6570\u9875\u9762WSGIRequestHandler\u7c7b\ncmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbWSGIRequestHandler\u8fdb\u5165\u6e90\u7801\n\u4f4d\u7f6e:wsgiref\u6a21\u5757simple_server.py\u6587\u4ef6(\u7b2c71\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">class WSGIRequestHandler(BaseHTTPRequestHandler):\n\n    server_version = &quot;WSGIServer\/&quot; + __version__\n\n    def get_environ(self):\n        env = self.server.base_environ.copy()\n        env['SERVER_PROTOCOL'] = self.request_version\n        env['SERVER_SOFTWARE'] = self.server_version\n        env['REQUEST_METHOD'] = self.command\n        if '?' in self.path:\n            path,query = self.path.split('?',1)\n        else:\n            path,query = self.path,''\n\n        env['PATH_INFO'] = urllib.parse.unquote(path, 'iso-8859-1')\n        env['QUERY_STRING'] = query\n\n        host = self.address_string()\n        if host != self.client_address[0]:\n            env['REMOTE_HOST'] = host\n        env['REMOTE_ADDR'] = self.client_address[0]\n\n        if self.headers.get('content-type') is None:\n            env['CONTENT_TYPE'] = self.headers.get_content_type()\n        else:\n            env['CONTENT_TYPE'] = self.headers['content-type']\n\n        length = self.headers.get('content-length')\n        if length:\n            env['CONTENT_LENGTH'] = length\n\n        for k, v in self.headers.items():\n            k=k.replace('-','_').upper(); v=v.strip()\n            if k in env:\n                continue                    # skip content length, type,etc.\n            if 'HTTP_'+k in env:\n                env['HTTP_'+k] += ','+v     # comma-separate multiple headers\n            else:\n                env['HTTP_'+k] = v\n        return env\n\n    def get_stderr(self):\n        return sys.stderr\n\n    def handle(self):\n        &quot;&quot;&quot;Handle a single HTTP request&quot;&quot;&quot;\n\n        self.raw_requestline = self.rfile.readline(65537)\n        if len(self.raw_requestline) &gt; 65536:\n            self.requestline = ''\n            self.request_version = ''\n            self.command = ''\n            self.send_error(414)\n            return\n\n        if not self.parse_request(): # An error code has been sent, just exit\n            return\n\n        handler = ServerHandler(\n            self.rfile, self.wfile, self.get_stderr(), self.get_environ(),\n            multithread=False,\n        )\n        handler.request_handler = self      # backpointer for logging\n        handler.run(self.server.get_app())<\/code><\/pre>\n<p>\u6ca1\u6709<strong>init<\/strong>\u65b9\u6cd5,\u7ee7\u627fBaseHTTPRequestHandler\u7c7b,\u672c\u7c7b\u5b9a\u4e49\u4e86get_environ\u3001get_stderr\u3001handle\u4e09\u4e2a\u65b9\u6cd5,\u6211\u4eec\u7ee7\u7eed\u5f80\u4e0a\u627e\u7ee7\u627f\u7c7bBaseHTTPRequestHandler<\/p>\n<p>(2) wsgiref\u6a21\u5757simple_server.py\u6587\u4ef671\u884c\ncmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbBaseHTTPRequestHandler\u8fdb\u5165\u6e90\u7801\n\u4f4d\u7f6e:http\u6a21\u5757server.py\u6587\u4ef6(\u7b2c146\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):\n\n    &quot;&quot;&quot;HTTP request handler base class.\n\n    The following explanation of HTTP serves to guide you through the\n    code as well as to expose any misunderstandings I may have about\n    HTTP (so you don't need to read the code to figure out I'm wrong\n    :-).\n\n    HTTP (HyperText Transfer Protocol) is an extensible protocol on\n    top of a reliable stream transport (e.g. TCP\/IP).  The protocol\n    recognizes three parts to a request:\n\n    1. One line identifying the request type and path\n    2. An optional set of RFC-822-style headers\n    3. An optional data part\n\n    The headers and data are separated by a blank line.\n\n    The first line of the request has the form\n\n&lt;command&gt; &lt;path&gt; &lt;version&gt;\n\n    where \n&lt;command&gt; is a (case-sensitive) keyword such as GET or POST,\n\n&lt;path&gt; is a string containing path information for the request,\n    and \n&lt;version&gt; should be the string &quot;HTTP\/1.0&quot; or &quot;HTTP\/1.1&quot;.\n\n&lt;path&gt; is encoded using the URL encoding scheme (using %xx to signify\n    the ASCII character with hex code xx).\n\n    The specification specifies that lines are separated by CRLF but\n    for compatibility with the widest range of clients recommends\n    servers also handle LF.  Similarly, whitespace in the request line\n    is treated sensibly (allowing multiple spaces between components\n    and allowing trailing whitespace).\n\n    Similarly, for output, lines ought to be separated by CRLF pairs\n    but most clients grok LF characters just fine.\n\n    If the first line of the request has the form\n\n&lt;command&gt; &lt;path&gt;\n\n    (i.e. \n&lt;version&gt; is left out) then this is assumed to be an HTTP\n    0.9 request; this form has no optional headers and data part and\n    the reply consists of just the data.\n\n    The reply form of the HTTP 1.x protocol again has three parts:\n\n    1. One line giving the response code\n    2. An optional set of RFC-822-style headers\n    3. The data\n\n    Again, the headers and data are separated by a blank line.\n\n    The response code line has the form\n\n&lt;version&gt; &lt;responsecode&gt; &lt;responsestring&gt;\n\n    where \n&lt;version&gt; is the protocol version (&quot;HTTP\/1.0&quot; or &quot;HTTP\/1.1&quot;),\n\n&lt;responsecode&gt; is a 3-digit response code indicating success or\n    failure of the request, and \n&lt;responsestring&gt; is an optional\n    human-readable string explaining what the response code means.\n\n    This server parses the request and the headers, and then calls a\n    function specific to the request type (\n&lt;command&gt;).  Specifically,\n    a request SPAM will be handled by a method do_SPAM().  If no\n    such method exists the server sends an error response to the\n    client.  If it exists, it is called with no arguments:\n\n    do_SPAM()\n\n    Note that the request name is case sensitive (i.e. SPAM and spam\n    are different requests).\n\n    The various request details are stored in instance variables:\n\n    - client_address is the client IP address in the form (host,\n    port);\n\n    - command, path and version are the broken-down request line;\n\n    - headers is an instance of email.message.Message (or a derived\n    class) containing the header information;\n\n    - rfile is a file object open for reading positioned at the\n    start of the optional input data part;\n\n    - wfile is a file object open for writing.\n\n    IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!\n\n    The first thing to be written must be the response line.  Then\n    follow 0 or more header lines, then a blank line, and then the\n    actual data (if any).  The meaning of the header lines depends on\n    the command executed by the server; in most cases, when data is\n    returned, there should be at least one header line of the form\n\n    Content-type: \n&lt;type&gt;\/&lt;subtype&gt;\n\n    where \n&lt;type&gt; and &lt;subtype&gt; should be registered MIME types,\n    e.g. &quot;text\/html&quot; or &quot;text\/plain&quot;.\n\n    &quot;&quot;&quot;\n\n    # The Python system version, truncated to its first component.\n    sys_version = &quot;Python\/&quot; + sys.version.split()[0]\n\n    # The server software version.  You may want to override this.\n    # The format is multiple whitespace-separated strings,\n    # where each string is of the form name[\/version].\n    server_version = &quot;BaseHTTP\/&quot; + __version__\n\n    error_message_format = DEFAULT_ERROR_MESSAGE\n    error_content_type = DEFAULT_ERROR_CONTENT_TYPE\n\n    # The default request version.  This only affects responses up until\n    # the point where the request line is parsed, so it mainly decides what\n    # the client gets back when sending a malformed request line.\n    # Most web servers default to HTTP 0.9, i.e. don't send a status line.\n    default_request_version = &quot;HTTP\/0.9&quot;\n\n    def parse_request(self):\n        &quot;&quot;&quot;Parse a request (internal).\n\n        The request should be stored in self.raw_requestline; the results\n        are in self.command, self.path, self.request_version and\n        self.headers.\n\n        Return True for success, False for failure; on failure, any relevant\n        error response has already been sent back.\n\n        &quot;&quot;&quot;\n        self.command = None  # set in case of error on the first line\n        self.request_version = version = self.default_request_version\n        self.close_connection = True\n        requestline = str(self.raw_requestline, 'iso-8859-1')\n        requestline = requestline.rstrip('\\r\\n')\n        self.requestline = requestline\n        words = requestline.split()\n        if len(words) == 0:\n            return False\n\n        if len(words) &gt;= 3:  # Enough to determine protocol version\n            version = words[-1]\n            try:\n                if not version.startswith('HTTP\/'):\n                    raise ValueError\n                base_version_number = version.split('\/', 1)[1]\n                version_number = base_version_number.split(&quot;.&quot;)\n                # RFC 2145 section 3.1 says there can be only one &quot;.&quot; and\n                #   - major and minor numbers MUST be treated as\n                #      separate integers;\n                #   - HTTP\/2.4 is a lower version than HTTP\/2.13, which in\n                #      turn is lower than HTTP\/12.3;\n                #   - Leading zeros MUST be ignored by recipients.\n                if len(version_number) != 2:\n                    raise ValueError\n                if any(not component.isdigit() for component in version_number):\n                    raise ValueError(&quot;non digit in http version&quot;)\n                if any(len(component) &gt; 10 for component in version_number):\n                    raise ValueError(&quot;unreasonable length http version&quot;)\n                version_number = int(version_number[0]), int(version_number[1])\n            except (ValueError, IndexError):\n                self.send_error(\n                    HTTPStatus.BAD_REQUEST,\n                    &quot;Bad request version (%r)&quot; % version)\n                return False\n            if version_number &gt;= (1, 1) and self.protocol_version &gt;= &quot;HTTP\/1.1&quot;:\n                self.close_connection = False\n            if version_number &gt;= (2, 0):\n                self.send_error(\n                    HTTPStatus.HTTP_VERSION_NOT_SUPPORTED,\n                    &quot;Invalid HTTP version (%s)&quot; % base_version_number)\n                return False\n            self.request_version = version\n\n        if not 2 &lt;= len(words) &lt;= 3:\n            self.send_error(\n                HTTPStatus.BAD_REQUEST,\n                &quot;Bad request syntax (%r)&quot; % requestline)\n            return False\n        command, path = words[:2]\n        if len(words) == 2:\n            self.close_connection = True\n            if command != 'GET':\n                self.send_error(\n                    HTTPStatus.BAD_REQUEST,\n                    &quot;Bad HTTP\/0.9 request type (%r)&quot; % command)\n                return False\n        self.command, self.path = command, path\n\n        # gh-87389: The purpose of replacing '\/\/' with '\/' is to protect\n        # against open redirect attacks possibly triggered if the path starts\n        # with '\/\/' because http clients treat \/\/path as an absolute URI\n        # without scheme (similar to http:\/\/path) rather than a path.\n        if self.path.startswith('\/\/'):\n            self.path = '\/' + self.path.lstrip('\/')  # Reduce to a single \/\n\n        # Examine the headers and look for a Connection directive.\n        try:\n            self.headers = http.client.parse_headers(self.rfile,\n                                                     _class=self.MessageClass)\n        except http.client.LineTooLong as err:\n            self.send_error(\n                HTTPStatus.REQUEST_HEADER_FIELDS_TOO_LARGE,\n                &quot;Line too long&quot;,\n                str(err))\n            return False\n        except http.client.HTTPException as err:\n            self.send_error(\n                HTTPStatus.REQUEST_HEADER_FIELDS_TOO_LARGE,\n                &quot;Too many headers&quot;,\n                str(err)\n            )\n            return False\n\n        conntype = self.headers.get('Connection', &quot;&quot;)\n        if conntype.lower() == 'close':\n            self.close_connection = True\n        elif (conntype.lower() == 'keep-alive' and\n              self.protocol_version &gt;= &quot;HTTP\/1.1&quot;):\n            self.close_connection = False\n        # Examine the headers and look for an Expect directive\n        expect = self.headers.get('Expect', &quot;&quot;)\n        if (expect.lower() == &quot;100-continue&quot; and\n                self.protocol_version &gt;= &quot;HTTP\/1.1&quot; and\n                self.request_version &gt;= &quot;HTTP\/1.1&quot;):\n            if not self.handle_expect_100():\n                return False\n        return True\n\n    def handle_expect_100(self):\n        &quot;&quot;&quot;Decide what to do with an &quot;Expect: 100-continue&quot; header.\n\n        If the client is expecting a 100 Continue response, we must\n        respond with either a 100 Continue or a final response before\n        waiting for the request body. The default is to always respond\n        with a 100 Continue. You can behave differently (for example,\n        reject unauthorized requests) by overriding this method.\n\n        This method should either return True (possibly after sending\n        a 100 Continue response) or send an error response and return\n        False.\n\n        &quot;&quot;&quot;\n        self.send_response_only(HTTPStatus.CONTINUE)\n        self.end_headers()\n        return True\n\n    def handle_one_request(self):\n        &quot;&quot;&quot;Handle a single HTTP request.\n\n        You normally don't need to override this method; see the class\n        __doc__ string for information on how to handle specific HTTP\n        commands such as GET and POST.\n\n        &quot;&quot;&quot;\n        try:\n            self.raw_requestline = self.rfile.readline(65537)\n            if len(self.raw_requestline) &gt; 65536:\n                self.requestline = ''\n                self.request_version = ''\n                self.command = ''\n                self.send_error(HTTPStatus.REQUEST_URI_TOO_LONG)\n                return\n            if not self.raw_requestline:\n                self.close_connection = True\n                return\n            if not self.parse_request():\n                # An error code has been sent, just exit\n                return\n            mname = 'do_' + self.command\n            if not hasattr(self, mname):\n                self.send_error(\n                    HTTPStatus.NOT_IMPLEMENTED,\n                    &quot;Unsupported method (%r)&quot; % self.command)\n                return\n            method = getattr(self, mname)\n            method()\n            self.wfile.flush() #actually send the response if not already done.\n        except TimeoutError as e:\n            #a read or a write timed out.  Discard this connection\n            self.log_error(&quot;Request timed out: %r&quot;, e)\n            self.close_connection = True\n            return\n\n    def handle(self):\n        &quot;&quot;&quot;Handle multiple requests if necessary.&quot;&quot;&quot;\n        self.close_connection = True\n\n        self.handle_one_request()\n        while not self.close_connection:\n            self.handle_one_request()\n\n    def send_error(self, code, message=None, explain=None):\n        &quot;&quot;&quot;Send and log an error reply.\n\n        Arguments are\n        * code:    an HTTP error code\n                   3 digits\n        * message: a simple optional 1 line reason phrase.\n                   *( HTAB \/ SP \/ VCHAR \/ %x80-FF )\n                   defaults to short entry matching the response code\n        * explain: a detailed message defaults to the long entry\n                   matching the response code.\n\n        This sends an error response (so it must be called before any\n        output has been generated), logs the error, and finally sends\n        a piece of HTML explaining the error to the user.\n\n        &quot;&quot;&quot;\n\n        try:\n            shortmsg, longmsg = self.responses[code]\n        except KeyError:\n            shortmsg, longmsg = '???', '???'\n        if message is None:\n            message = shortmsg\n        if explain is None:\n            explain = longmsg\n        self.log_error(&quot;code %d, message %s&quot;, code, message)\n        self.send_response(code, message)\n        self.send_header('Connection', 'close')\n\n        # Message body is omitted for cases described in:\n        #  - RFC7230: 3.3. 1xx, 204(No Content), 304(Not Modified)\n        #  - RFC7231: 6.3.6. 205(Reset Content)\n        body = None\n        if (code &gt;= 200 and\n            code not in (HTTPStatus.NO_CONTENT,\n                         HTTPStatus.RESET_CONTENT,\n                         HTTPStatus.NOT_MODIFIED)):\n            # HTML encode to prevent Cross Site Scripting attacks\n            # (see bug #1100201)\n            content = (self.error_message_format % {\n                'code': code,\n                'message': html.escape(message, quote=False),\n                'explain': html.escape(explain, quote=False)\n            })\n            body = content.encode('UTF-8', 'replace')\n            self.send_header(&quot;Content-Type&quot;, self.error_content_type)\n            self.send_header('Content-Length', str(len(body)))\n        self.end_headers()\n\n        if self.command != 'HEAD' and body:\n            self.wfile.write(body)\n\n    def send_response(self, code, message=None):\n        &quot;&quot;&quot;Add the response header to the headers buffer and log the\n        response code.\n\n        Also send two standard headers with the server software\n        version and the current date.\n\n        &quot;&quot;&quot;\n        self.log_request(code)\n        self.send_response_only(code, message)\n        self.send_header('Server', self.version_string())\n        self.send_header('Date', self.date_time_string())\n\n    def send_response_only(self, code, message=None):\n        &quot;&quot;&quot;Send the response header only.&quot;&quot;&quot;\n        if self.request_version != 'HTTP\/0.9':\n            if message is None:\n                if code in self.responses:\n                    message = self.responses[code][0]\n                else:\n                    message = ''\n            if not hasattr(self, '_headers_buffer'):\n                self._headers_buffer = []\n            self._headers_buffer.append((&quot;%s %d %s\\r\\n&quot; %\n                    (self.protocol_version, code, message)).encode(\n                        'latin-1', 'strict'))\n\n    def send_header(self, keyword, value):\n        &quot;&quot;&quot;Send a MIME header to the headers buffer.&quot;&quot;&quot;\n        if self.request_version != 'HTTP\/0.9':\n            if not hasattr(self, '_headers_buffer'):\n                self._headers_buffer = []\n            self._headers_buffer.append(\n                (&quot;%s: %s\\r\\n&quot; % (keyword, value)).encode('latin-1', 'strict'))\n\n        if keyword.lower() == 'connection':\n            if value.lower() == 'close':\n                self.close_connection = True\n            elif value.lower() == 'keep-alive':\n                self.close_connection = False\n\n    def end_headers(self):\n        &quot;&quot;&quot;Send the blank line ending the MIME headers.&quot;&quot;&quot;\n        if self.request_version != 'HTTP\/0.9':\n            self._headers_buffer.append(b&quot;\\r\\n&quot;)\n            self.flush_headers()\n\n    def flush_headers(self):\n        if hasattr(self, '_headers_buffer'):\n            self.wfile.write(b&quot;&quot;.join(self._headers_buffer))\n            self._headers_buffer = []\n\n    def log_request(self, code='-', size='-'):\n        &quot;&quot;&quot;Log an accepted request.\n\n        This is called by send_response().\n\n        &quot;&quot;&quot;\n        if isinstance(code, HTTPStatus):\n            code = code.value\n        self.log_message('&quot;%s&quot; %s %s',\n                         self.requestline, str(code), str(size))\n\n    def log_error(self, format, *args):\n        &quot;&quot;&quot;Log an error.\n\n        This is called when a request cannot be fulfilled.  By\n        default it passes the message on to log_message().\n\n        Arguments are the same as for log_message().\n\n        XXX This should go to the separate error log.\n\n        &quot;&quot;&quot;\n\n        self.log_message(format, *args)\n\n    # https:\/\/en.wikipedia.org\/wiki\/List_of_Unicode_characters#Control_codes\n    _control_char_table = str.maketrans(\n            {c: fr'\\x{c:02x}' for c in itertools.chain(range(0x20), range(0x7f,0xa0))})\n    _control_char_table[ord('\\\\')] = r'\\\\'\n\n    def log_message(self, format, *args):\n        &quot;&quot;&quot;Log an arbitrary message.\n\n        This is used by all other logging functions.  Override\n        it if you have specific logging wishes.\n\n        The first argument, FORMAT, is a format string for the\n        message to be logged.  If the format string contains\n        any % escapes requiring parameters, they should be\n        specified as subsequent arguments (it's just like\n        printf!).\n\n        The client ip and current date\/time are prefixed to\n        every message.\n\n        Unicode control characters are replaced with escaped hex\n        before writing the output to stderr.\n\n        &quot;&quot;&quot;\n\n        message = format % args\n        sys.stderr.write(&quot;%s - - [%s] %s\\n&quot; %\n                         (self.address_string(),\n                          self.log_date_time_string(),\n                          message.translate(self._control_char_table)))\n\n    def version_string(self):\n        &quot;&quot;&quot;Return the server software version string.&quot;&quot;&quot;\n        return self.server_version + ' ' + self.sys_version\n\n    def date_time_string(self, timestamp=None):\n        &quot;&quot;&quot;Return the current date and time formatted for a message header.&quot;&quot;&quot;\n        if timestamp is None:\n            timestamp = time.time()\n        return email.utils.formatdate(timestamp, usegmt=True)\n\n    def log_date_time_string(self):\n        &quot;&quot;&quot;Return the current time formatted for logging.&quot;&quot;&quot;\n        now = time.time()\n        year, month, day, hh, mm, ss, x, y, z = time.localtime(now)\n        s = &quot;%02d\/%3s\/%04d %02d:%02d:%02d&quot; % (\n                day, self.monthname[month], year, hh, mm, ss)\n        return s\n\n    weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n\n    monthname = [None,\n                 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\n                 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']\n\n    def address_string(self):\n        &quot;&quot;&quot;Return the client address.&quot;&quot;&quot;\n\n        return self.client_address[0]\n\n    # Essentially static class variables\n\n    # The version of the HTTP protocol we support.\n    # Set this to HTTP\/1.1 to enable automatic keepalive\n    protocol_version = &quot;HTTP\/1.0&quot;\n\n    # MessageClass used to parse headers\n    MessageClass = http.client.HTTPMessage\n\n    # hack to maintain backwards compatibility\n    responses = {\n        v: (v.phrase, v.description)\n        for v in HTTPStatus.__members__.values()\n    }\n<\/code><\/pre>\n<p>\u6ca1\u6709<strong>init<\/strong>\u65b9\u6cd5,\u7ee7\u627fsocketserver.StreamRequestHandler\u7c7b,\u6211\u4eec\u7ee7\u7eed\u5f80\u4e0a\u627e\u7ee7\u627f\u7c7bsocketserver.StreamRequestHandler<\/p>\n<p>(3) http\u6a21\u5757server.py\u6587\u4ef6\u7b2c146\u884c\ncmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbsocketserver.StreamRequestHandler\u8fdb\u5165\u6e90\u7801\n\u4f4d\u7f6e:socketserver\u6a21\u5757socketserver.py\u6587\u4ef6(\u7b2c788\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">class StreamRequestHandler(BaseRequestHandler):\n\n    &quot;&quot;&quot;Define self.rfile and self.wfile for stream sockets.&quot;&quot;&quot;\n\n    # Default buffer sizes for rfile, wfile.\n    # We default rfile to buffered because otherwise it could be\n    # really slow for large data (a getc() call per byte); we make\n    # wfile unbuffered because (a) often after a write() we want to\n    # read and we need to flush the line; (b) big writes to unbuffered\n    # files are typically optimized by stdio even when big reads\n    # aren't.\n    rbufsize = -1\n    wbufsize = 0\n\n    # A timeout to apply to the request socket, if not None.\n    timeout = None\n\n    # Disable nagle algorithm for this socket, if True.\n    # Use only when wbufsize != 0, to avoid small packets.\n    disable_nagle_algorithm = False\n\n    def setup(self):\n        self.connection = self.request\n        if self.timeout is not None:\n            self.connection.settimeout(self.timeout)\n        if self.disable_nagle_algorithm:\n            self.connection.setsockopt(socket.IPPROTO_TCP,\n                                       socket.TCP_NODELAY, True)\n        self.rfile = self.connection.makefile('rb', self.rbufsize)\n        if self.wbufsize == 0:\n            self.wfile = _SocketWriter(self.connection)\n        else:\n            self.wfile = self.connection.makefile('wb', self.wbufsize)\n\n    def finish(self):\n        if not self.wfile.closed:\n            try:\n                self.wfile.flush()\n            except socket.error:\n                # A final socket error may have occurred here, such as\n                # the local error ECONNABORTED.\n                pass\n        self.wfile.close()\n        self.rfile.close()\n<\/code><\/pre>\n<p>\u6ca1\u6709<strong>init<\/strong>\u65b9\u6cd5,\u7ee7\u627fBaseRequestHandler\u7c7b,\u6211\u4eec\u7ee7\u7eed\u5f80\u4e0a\u627e\u7ee7\u627f\u7c7bBaseRequestHandler<\/p>\n<p>(4) socketserver\u6a21\u5757socketserver.py\u6587\u4ef6\u7b2c788\u884c\ncmd+\u9f20\u6807\u5de6\u952e -&gt;\u70b9\u51fbBaseRequestHandler\u8fdb\u5165\u6e90\u7801\n\u4f4d\u7f6e:socketserver\u6a21\u5757socketserver.py\u6587\u4ef6(\u7b2c742\u884c,\u4e0d\u540c\u7248\u672c\u53ef\u80fd\u884c\u6570\u7a0d\u5fae\u4e0d\u4e00\u6837)<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseRequestHandler:\n\n    &quot;&quot;&quot;Base class for request handler classes.\n\n    This class is instantiated for each request to be handled.  The\n    constructor sets the instance variables request, client_address\n    and server, and then calls the handle() method.  To implement a\n    specific service, all you need to do is to derive a class which\n    defines a handle() method.\n\n    The handle() method can find the request as self.request, the\n    client address as self.client_address, and the server (in case it\n    needs access to per-server information) as self.server.  Since a\n    separate instance is created for each request, the handle() method\n    can define other arbitrary instance variables.\n\n    &quot;&quot;&quot;\n\n    def __init__(self, request, client_address, server):\n        self.request = request\n        self.client_address = client_address\n        self.server = server\n        self.setup()\n        try:\n            self.handle()\n        finally:\n            self.finish()\n\n    def setup(self):\n        pass\n\n    def handle(self):\n        pass\n\n    def finish(self):\n        pass\n<\/code><\/pre>\n<p><strong><em>\u5230\u8fd9\u91cc\u6211\u4eec\u7406\u6e05\u4e86\u7c7b\u7ee7\u627f\u5173\u7cfb<\/em><\/strong>\nWSGIRequestHandler-&gt;BaseHTTPRequestHandler-&gt;socketserver.StreamRequestHandler-&gt;BaseRequestHandler<\/p>\n<p>BaseRequestHandler\u7c7b\u5c31\u662f\u57fa\u7c7b,\u6709<strong>init<\/strong>\u521d\u59cb\u5316\u65b9\u6cd5\u3002\u4ece\u4e0a\u9762\u4ee3\u7801\u770b\u51fa\u521d\u59cb\u5316\u65b9\u6cd5\u901a\u8fc7\u4f20\u9012\u8fdb\u6765\u7684\u53c2\u6570\u521d\u59cb\u53163\u4e2a\u5c5e\u6027\u540e\u8c03\u7528\u4e86self.setup()\u65b9\u6cd5,\u7136\u540e\u6267\u884c\u4e86self.handle()\u65b9\u6cd5,\u6700\u540e\u6267\u884cself.finish()\u65b9\u6cd5,\u8fd93\u4e2a\u65b9\u6cd5\u6ca1\u6709\u5728\u57fa\u7c7b\u578b\u5b9a\u4e49,\u80af\u5b9a\u5728\u67d0\u4e2a\u7ee7\u627f\u7c7b\u5b9e\u73b0\u4e86,\u6211\u4eec\u6309\u7167\u5c31\u8fd1\u539f\u5219\u9010\u5c42\u67e5\u5230\u3002\nsetup()\u65b9\u6cd5\u5728StreamRequestHandler\u7c7b\u4e2d\u6709\u5b9a\u4e49<\/p>\n<pre><code class=\"lang-python language-python python\">class StreamRequestHandler(BaseRequestHandler):\n    ...\n    def setup(self):\n        # \u3010\u7b2c 1 \u884c\u3011\u5c06\u7236\u7c7b\u63a5\u6536\u5230\u7684\u7269\u7406\u5957\u63a5\u5b57\uff08self.request\uff09\u8d4b\u503c\u7ed9 self.connection\uff08\u8d77\u4e00\u4e2a\u66f4\u597d\u61c2\u7684\u522b\u540d\uff09\n        self.connection = self.request\n\n        # \u3010\u7b2c 2 \u884c\u3011\u5224\u65ad\u670d\u52a1\u5668\u6709\u6ca1\u6709\u8bbe\u7f6e\u8d85\u65f6\u65f6\u95f4\uff08timeout\uff09\n        if self.timeout is not None:\n            # \u3010\u7b2c 3 \u884c\u3011\u7ed9\u5e95\u5c42\u7f51\u7edc\u8fde\u63a5\u8bbe\u7f6e\u8d85\u65f6\u9632\u7ebf\uff0c\u8d85\u8fc7\u8fd9\u4e2a\u65f6\u95f4\u6d4f\u89c8\u5668\u4e0d\u53d1\u6570\u636e\uff0c\u7269\u7406\u8fde\u63a5\u7acb\u523b\u88ab\u5f3a\u884c\u65ad\u5f00\n            self.connection.settimeout(self.timeout)\n\n        # \u3010\u7b2c 4 \u884c\u3011\u5224\u65ad\u662f\u5426\u9700\u8981\u7981\u7528\u64cd\u4f5c\u7cfb\u7edf\u7684 Nagle\uff08\u7eb3\u683c\uff09\u7b97\u6cd5\uff08\u9ed8\u8ba4\u5ef6\u8fdf\u62fc\u5305\u7b97\u6cd5\uff09\n        if self.disable_nagle_algorithm:\n            # \u3010\u7b2c 5 \u884c\u3011\u5e95\u5c42\u7cfb\u7edf\u8c03\u7528\uff1a\u5f00\u542f TCP_NODELAY\uff0c\u5f3a\u5236\u7f51\u5361\u6709\u6570\u636e\u7acb\u523b\u5c04\u51fa\u7f51\u7ebf\uff0c\u5b9e\u73b0 Web \u670d\u52a1\u7684\u8d85\u4f4e\u5ef6\u8fdf\u54cd\u5e94\n            self.connection.setsockopt(socket.IPPROTO_TCP,\n                                       socket.TCP_NODELAY, True)\n\n        # \u3010\u7b2c 6 \u884c\u3011\ud83c\udf1f \u6838\u5fc3\u9b54\u6cd5\uff1a\u5c06\u7f51\u7edc\u8fde\u63a5\u5305\u88c5\u6210&ldquo;\u4e8c\u8fdb\u5236\u53ea\u8bfb\u6587\u4ef6\u5bf9\u8c61\uff08rfile\uff09&rdquo;\uff0c\u8bbe\u7f6e\u7f13\u51b2\u533a\u5927\u5c0f\u4e3a self.rbufsize\n        # \u4ece\u6b64\u540e\u7eed\u7684 wsgiref \u5904\u7406\u5668\u5c31\u53ef\u4ee5\u7528 self.rfile.readline() \u50cf\u8bfb\u672c\u5730\u6587\u4ef6\u4e00\u6837\u4f18\u96c5\u5730\u4e00\u884c\u884c\u89e3\u6790 HTTP \u6587\u672c\u4e86\n        self.rfile = self.connection.makefile('rb', self.rbufsize)\n\n        # \u3010\u7b2c 7 \u884c\u3011\u5224\u65ad\u5199\u7f13\u51b2\u533a\u5927\u5c0f\uff08wbufsize\uff09\u662f\u5426\u8bbe\u7f6e\u4e3a 0\uff08\u5373\u4e0d\u5f00\u542f\u7f13\u51b2\u533a\uff0c\u53ea\u8981\u6709\u54cd\u5e94\u6570\u636e\u7acb\u523b\u7269\u7406\u5199\u5165\u7f51\u5361\uff09\n        if self.wbufsize == 0:\n            # \u3010\u7b2c 8 \u884c\u3011\u5982\u679c\u4e0d\u5f00\u542f\u7f13\u51b2\u533a\uff0c\u4f7f\u7528\u5185\u7f6e\u7684 _SocketWriter \u5305\u88c5\u8fde\u63a5\uff0c\u786e\u4fdd write \u7684\u6570\u636e\u767e\u5206\u4e4b\u767e\u6ca1\u6709\u5ef6\u8fdf\u5730\u53d1\u8d70\n            self.wfile = _SocketWriter(self.connection)\n        else:\n            # \u3010\u7b2c 9 \u884c\u3011\u5982\u679c\u5f00\u542f\u4e86\u5199\u7f13\u51b2\uff0c\u901a\u8fc7 makefile('wb') \u5c06\u7f51\u7edc\u8fde\u63a5\u5305\u88c5\u6210&ldquo;\u4e8c\u8fdb\u5236\u53ea\u5199\u6587\u4ef6\u5bf9\u8c61\uff08wfile\uff09&rdquo;\n            # \u6570\u636e\u4f1a\u5148\u6682\u5b58\u5728\u5185\u5b58\u7f13\u51b2\u533a\u4e2d\uff0c\u7b49\u6512\u591f\u4e86\u6216\u8005\u6267\u884c\u4e86 flush() \u540e\u518d\u4e00\u6b21\u6027\u53d1\u8d70\uff0c\u6781\u5927\u5730\u51cf\u5c11\u4e86\u9891\u7e41\u64cd\u4f5c\u7f51\u5361\u7684\u7cfb\u7edf\u5f00\u9500\n            self.wfile = self.connection.makefile('wb', self.wbufsize)<\/code><\/pre>\n<p>\u8fd9\u6bb5\u4ee3\u7801\u628a\u64cd\u4f5c\u7cfb\u7edf\u7684\u539f\u59cb Socket \u5957\u63a5\u5b57\uff08\u7f51\u7edc\u5b57\u8282\u6d41\uff09\u9b54\u6539\u3001\u5305\u88c5\u6210\u6807\u51c6 Python \u201c\u6587\u4ef6\u5bf9\u8c61\u201d\u7684\u52a0\u5de5\u5382\uff01<\/p>\n<p>handle()\u65b9\u6cd5\u5728WSGIRequestHandler\u7c7b\u4e2d\u6709\u91cd\u5199<\/p>\n<pre><code class=\"lang-python language-python python\">class WSGIRequestHandler(BaseHTTPRequestHandler):\n ...\n def handle(self):\n        &quot;&quot;&quot;Handle a single HTTP request&quot;&quot;&quot;\n\n        self.raw_requestline = self.rfile.readline(65537)\n        if len(self.raw_requestline) &gt; 65536:\n            self.requestline = ''\n            self.request_version = ''\n            self.command = ''\n            self.send_error(414)\n            return\n\n        if not self.parse_request(): # An error code has been sent, just exit\n            return\n\n        handler = ServerHandler(\n            self.rfile, self.wfile, self.get_stderr(), self.get_environ(),\n            multithread=False,\n        )\n        handler.request_handler = self      # backpointer for logging\n        handler.run(self.server.get_app())<\/code><\/pre>\n<p>\u8fd9\u6bb5\u4ee3\u7801\u5c31\u662f\u6574\u4e2a\u542f\u52a8\u7684\u6838\u5fc3\uff0c\u5176\u4e2d<\/p>\n<pre><code class=\"lang-python language-python python\"># \u3010\u7b2c 1 \u884c\u3011\ud83c\udf1f \u8054\u52a8\u4f0f\u7ebf\uff1a\u901a\u8fc7\u521a\u521a\u5728 setup() \u91cc\u52a0\u5de5\u51fa\u6765\u7684 rfile \u6587\u4ef6\u6d41\u5bf9\u8c61\uff0c\u5c1d\u8bd5\u8bfb\u53d6\u8bf7\u6c42\u7684\u7b2c\u4e00\u884c\n# \u4f20\u5165\u53c2\u6570 65537 \u610f\u5473\u7740\uff1a\u5e95\u5c42\u6700\u591a\u53ea\u8bfb 65537 \u4e2a\u5b57\u8282\uff0c\u4e00\u65e6\u8d85\u8fc7\u8fd9\u4e2a\u957f\u5ea6\u5c31\u4f1a\u76f4\u63a5\u622a\u65ad\u8fd4\u56de\uff0c\u7edd\u4e0d\u591a\u8bfb\uff01\nself.raw_requestline = self.rfile.readline(65537)\n\n# \u3010\u7b2c 2 \u884c\u3011\u5b89\u5168\u9632\u7ebf\u68c0\u67e5\uff1a\u5224\u65ad\u8bfb\u5230\u7684\u8fd9\u7b2c\u4e00\u884c\u8bf7\u6c42\uff08URL+\u8bf7\u6c42\u5934\u7b2c\u4e00\u884c\uff09\u662f\u5426\u8d85\u8fc7\u4e86 64KB\uff0865536 \u5b57\u8282\uff09\nif len(self.raw_requestline) &gt; 65536:\n    # \u3010\u7b2c 3~5 \u884c\u3011\u5982\u679c\u8d85\u957f\u4e86\uff0c\u5224\u5b9a\u4e3a\u975e\u6cd5\u8bf7\u6c42\u3002\u5c06\u5185\u90e8\u7684\u8bf7\u6c42\u884c\u3001HTTP \u7248\u672c\u3001\u8bf7\u6c42\u65b9\u6cd5\u7b49\u5c5e\u6027\u5168\u90e8\u6e05\u7a7a\u62b9\u9664\n    self.requestline = ''\n    self.request_version = ''\n    self.command = ''\n\n    # \u3010\u7b2c 6 \u884c\u3011\u5411\u6d4f\u89c8\u5668\u629b\u51fa\u6807\u51c6\u7684 HTTP 414 \u72b6\u6001\u7801\uff08414 URI Too Long\uff0c\u610f\u601d\u662f URL \u957f\u5ea6\u8d85\u8fc7\u670d\u52a1\u5668\u9650\u5236\uff09\n    self.send_error(414)\n\n    # \u3010\u7b2c 7 \u884c\u3011\u7acb\u523b return \u9000\u51fa\u51fd\u6570\uff01\u7edd\u5bf9\u4e0d\u518d\u5411\u540e\u6267\u884c\u4efb\u4f55\u89e3\u6790\u903b\u8f91\uff0c\u76f4\u63a5\u65ad\u5f00\u4e0e\u5ba2\u6237\u7aef\u7684\u8fde\u63a5\n    return\n\n# \u3010\u7b2c 8 \u884c\u3011\u6838\u5fc3\u89e3\u6790\uff1a\u5982\u679c\u901a\u8fc7\u4e86 64KB \u5b89\u5168\u68c0\u67e5\uff0c\u8c03\u7528 parse_request() \u65b9\u6cd5\u5bf9\u8fd9\u884c\u7eaf\u6587\u672c\u8fdb\u884c\u5207\u7247\u548c\u62c6\u89e3\n# \u5982\u679c\u89e3\u6790\u5931\u8d25\uff08\u4f8b\u5982\u6d4f\u89c8\u5668\u4f20\u8fc7\u6765\u7684\u6587\u672c\u4e0d\u7b26\u5408 HTTP \u534f\u8bae\u89c4\u8303\uff09\nif not self.parse_request(): # \u6b64\u65f6\u5185\u90e8\u5df2\u7ecf\u53d1\u9001\u4e86\u76f8\u5e94\u7684 HTTP \u9519\u8bef\u72b6\u6001\u7801\n    # \u3010\u7b2c 9 \u884c\u3011\u76f4\u63a5 return \u9000\u51fa\uff0c\u4e0d\u518d\u5411\u4e0b\u6267\u884c\u4e1a\u52a1\u903b\u8f91\n    return\n<\/code><\/pre>\n<p>\u8fd9\u6bb5\u4ee3\u7801\u662f wsgiref.simple_server.WSGIRequestHandler \u91cc\u7684 handle() \u65b9\u6cd5\u7684\u5f00\u5934\u6bb5\u843d\u3002\u5b83\u662f\u7f51\u7edc\u670d\u52a1\u5668\u4e3a\u4e86\u5e94\u5bf9\u590d\u6742\u3001\u5371\u9669\u7684\u4e92\u8054\u7f51\u73af\u5883\u800c\u8bbe\u7acb\u7684\u7b2c\u4e00\u9053\u5b89\u5168\u9632\u7ebf\uff08\u9632\u7206\u76fe\uff09\u548c\u6838\u5fc3\u89e3\u6790\u5668\u3002\n\u6240\u4ee5\u6574\u4e2a\u6838\u5fc3\u805a\u7126\u5728\u8fd9\u4e00\u6bb5:<\/p>\n<pre><code class=\"lang-python language-python python\"> handler = ServerHandler(\n            self.rfile, self.wfile, self.get_stderr(), self.get_environ(),\n            multithread=False,\n        )\n        handler.request_handler = self      # backpointer for logging\n        handler.run(self.server.get_app())<\/code><\/pre>\n<p>\u5927\u610f\u662f\u4f7f\u7528 ServerHandler\u7c7b\u521d\u59cb\u5316\u4e86 handler \u5bf9\u8c61,\u7136\u540e\u8c03\u7528\u4e86run()\u65b9\u6cd5,run()\u65b9\u6cd5\u4f20\u9012\u7684\u5c31\u662fapplication\u5e94\u7528(self.server.get_app()),\u8fd9\u4e2a\u5728\u7c7bWSGIRequestHandler\u5bf9\u8c61\u521d\u59cb\u5316\u65f6,\u4f20\u9012server\u5bf9\u8c61\u8fc7\u53bb\u7684\u3002<\/p>\n<p>\u6211\u4eec\u63a5\u7740\u9700\u8981\u627e\u5230ServerHandler\u7c7b\u7684\u5b9a\u4e49\u53ca\u5176run()\u65b9\u6cd5\u5b9e\u73b0\u3002<\/p>\n<p>\u5728wsgiref\u6a21\u5757\u7684simple_server.py\u6587\u4ef628\u884c\u6709ServerHandler\u7c7b\u5b9a\u4e49,\u5176\u7ee7\u627fSimpleHandler\u7c7b\uff0c\u4ee3\u7801\u5982\u4e0b:<\/p>\n<pre><code class=\"lang-python language-python python\">class ServerHandler(SimpleHandler):\n\n    server_software = software_version\n\n    def close(self):\n        try:\n            self.request_handler.log_request(\n                self.status.split(' ',1)[0], self.bytes_sent\n            )\n        finally:\n            SimpleHandler.close(self)<\/code><\/pre>\n<p>\u70b9\u51fbcmd+\u9f20\u6807\u5de6\u952e\u70b9\u51fbSimpleHandler\u8fdb\u5165\u6e90\u4ee3\u7801\u4f4d\u7f6e\uff0c\u5728 wsgiref\u6a21\u5757\u7684handlers.py\u7684439\u884c\u627e\u5230\u4e86SimpleHandler\u7684\u5b9a\u4e49\u3002<\/p>\n<pre><code class=\"lang-python language-python python\">class SimpleHandler(BaseHandler):\n    &quot;&quot;&quot;Handler that's just initialized with streams, environment, etc.\n\n    This handler subclass is intended for synchronous HTTP\/1.0 origin servers,\n    and handles sending the entire response output, given the correct inputs.\n\n    Usage::\n\n        handler = SimpleHandler(\n            inp,out,err,env, multithread=False, multiprocess=True\n        )\n        handler.run(app)&quot;&quot;&quot;\n\n    def __init__(self,stdin,stdout,stderr,environ,\n        multithread=True, multiprocess=False\n    ):\n        self.stdin = stdin\n        self.stdout = stdout\n        self.stderr = stderr\n        self.base_env = environ\n        self.wsgi_multithread = multithread\n        self.wsgi_multiprocess = multiprocess\n\n    def get_stdin(self):\n        return self.stdin\n\n    def get_stderr(self):\n        return self.stderr\n\n    def add_cgi_vars(self):\n        self.environ.update(self.base_env)\n\n    def _write(self,data):\n        result = self.stdout.write(data)\n        if result is None or result == len(data):\n            return\n        from warnings import warn\n        warn(&quot;SimpleHandler.stdout.write() should not do partial writes&quot;,\n            DeprecationWarning)\n        while data := data[result:]:\n            result = self.stdout.write(data)\n\n    def _flush(self):\n        self.stdout.flush()\n        self._flush = self.stdout.flush<\/code><\/pre>\n<p>SimpleHandler\u7c7b\u4e2d\u5e76\u6ca1\u6709run()\u65b9\u6cd5,\u4f46\u662fSimpleHandler\u7c7b\u53c8\u7ee7\u627fBaseHandler\u7c7b,\u8fd9\u4e2a\u7c7b\u5e94\u8be5\u6709\u5b9a\u4e49\u3002\n\u70b9\u51fbcmd+\u9f20\u6807\u5de6\u952e\u70b9\u51fbBaseHandler\u8fdb\u5165\u6e90\u4ee3\u7801\u4f4d\u7f6e\uff0c\u5728 wsgiref\u6a21\u5757\u7684handlers.py\u768494\u884c\u627e\u5230\u4e86BaseHandler\u7684\u5b9a\u4e49,\u4ee3\u7801\u5982\u4e0b:<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseHandler:\n    &quot;&quot;&quot;Manage the invocation of a WSGI application&quot;&quot;&quot;\n\n    # Configuration parameters; can override per-subclass or per-instance\n    wsgi_version = (1,0)\n    wsgi_multithread = True\n    wsgi_multiprocess = True\n    wsgi_run_once = False\n\n    origin_server = True    # We are transmitting direct to client\n    http_version  = &quot;1.0&quot;   # Version that should be used for response\n    server_software = None  # String name of server software, if any\n\n    # os_environ is used to supply configuration from the OS environment:\n    # by default it's a copy of 'os.environ' as of import time, but you can\n    # override this in e.g. your __init__ method.\n    os_environ= read_environ()\n\n    # Collaborator classes\n    wsgi_file_wrapper = FileWrapper     # set to None to disable\n    headers_class = Headers             # must be a Headers-like class\n\n    # Error handling (also per-subclass or per-instance)\n    traceback_limit = None  # Print entire traceback to self.get_stderr()\n    error_status = &quot;500 Internal Server Error&quot;\n    error_headers = [('Content-Type','text\/plain')]\n    error_body = b&quot;A server error occurred.  Please contact the administrator.&quot;\n\n    # State variables (don't mess with these)\n    status = result = None\n    headers_sent = False\n    headers = None\n    bytes_sent = 0\n\n    def run(self, application):\n        &quot;&quot;&quot;Invoke the application&quot;&quot;&quot;\n        # Note to self: don't move the close()!  Asynchronous servers shouldn't\n        # call close() from finish_response(), so if you close() anywhere but\n        # the double-error branch here, you'll break asynchronous servers by\n        # prematurely closing.  Async servers must return from 'run()' without\n        # closing if there might still be output to iterate over.\n        try:\n            self.setup_environ()\n            self.result = application(self.environ, self.start_response)\n            self.finish_response()\n        except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):\n            # We expect the client to close the connection abruptly from time\n            # to time.\n            return\n        except:\n            try:\n                self.handle_error()\n            except:\n                # If we get an error handling an error, just give up already!\n                self.close()\n                raise   # ...and let the actual server figure it out.\n\n    def setup_environ(self):\n        &quot;&quot;&quot;Set up the environment for one request&quot;&quot;&quot;\n\n        env = self.environ = self.os_environ.copy()\n        self.add_cgi_vars()\n\n        env['wsgi.input']        = self.get_stdin()\n        env['wsgi.errors']       = self.get_stderr()\n        env['wsgi.version']      = self.wsgi_version\n        env['wsgi.run_once']     = self.wsgi_run_once\n        env['wsgi.url_scheme']   = self.get_scheme()\n        env['wsgi.multithread']  = self.wsgi_multithread\n        env['wsgi.multiprocess'] = self.wsgi_multiprocess\n\n        if self.wsgi_file_wrapper is not None:\n            env['wsgi.file_wrapper'] = self.wsgi_file_wrapper\n\n        if self.origin_server and self.server_software:\n            env.setdefault('SERVER_SOFTWARE',self.server_software)\n\n    def finish_response(self):\n        &quot;&quot;&quot;Send any iterable data, then close self and the iterable\n\n        Subclasses intended for use in asynchronous servers will\n        want to redefine this method, such that it sets up callbacks\n        in the event loop to iterate over the data, and to call\n        'self.close()' once the response is finished.\n        &quot;&quot;&quot;\n        try:\n            if not self.result_is_file() or not self.sendfile():\n                for data in self.result:\n                    self.write(data)\n                self.finish_content()\n        except:\n            # Call close() on the iterable returned by the WSGI application\n            # in case of an exception.\n            if hasattr(self.result, 'close'):\n                self.result.close()\n            raise\n        else:\n            # We only call close() when no exception is raised, because it\n            # will set status, result, headers, and environ fields to None.\n            # See bpo-29183 for more details.\n            self.close()\n\n    def get_scheme(self):\n        &quot;&quot;&quot;Return the URL scheme being used&quot;&quot;&quot;\n        return guess_scheme(self.environ)\n\n    def set_content_length(self):\n        &quot;&quot;&quot;Compute Content-Length or switch to chunked encoding if possible&quot;&quot;&quot;\n        try:\n            blocks = len(self.result)\n        except (TypeError,AttributeError,NotImplementedError):\n            pass\n        else:\n            if blocks==1:\n                self.headers['Content-Length'] = str(self.bytes_sent)\n                return\n        # XXX Try for chunked encoding if origin server and client is 1.1\n\n    def cleanup_headers(self):\n        &quot;&quot;&quot;Make any necessary header changes or defaults\n\n        Subclasses can extend this to add other defaults.\n        &quot;&quot;&quot;\n        if 'Content-Length' not in self.headers:\n            self.set_content_length()\n\n    def start_response(self, status, headers,exc_info=None):\n        &quot;&quot;&quot;'start_response()' callable as specified by PEP 3333&quot;&quot;&quot;\n\n        if exc_info:\n            try:\n                if self.headers_sent:\n                    raise\n            finally:\n                exc_info = None        # avoid dangling circular ref\n        elif self.headers is not None:\n            raise AssertionError(&quot;Headers already set!&quot;)\n\n        self.status = status\n        self.headers = self.headers_class(headers)\n        status = self._convert_string_type(status, &quot;Status&quot;)\n        self._validate_status(status)\n\n        if __debug__:\n            for name, val in headers:\n                name = self._convert_string_type(name, &quot;Header name&quot;)\n                val = self._convert_string_type(val, &quot;Header value&quot;)\n                assert not is_hop_by_hop(name),\\\n                       f&quot;Hop-by-hop header, '{name}: {val}', not allowed&quot;\n\n        return self.write\n\n    def _validate_status(self, status):\n        if len(status) &lt; 4:\n            raise AssertionError(&quot;Status must be at least 4 characters&quot;)\n        if not status[:3].isdigit():\n            raise AssertionError(&quot;Status message must begin w\/3-digit code&quot;)\n        if status[3] != &quot; &quot;:\n            raise AssertionError(&quot;Status message must have a space after code&quot;)\n\n    def _convert_string_type(self, value, title):\n        &quot;&quot;&quot;Convert\/check value type.&quot;&quot;&quot;\n        if type(value) is str:\n            return value\n        raise AssertionError(\n            &quot;{0} must be of type str (got {1})&quot;.format(title, repr(value))\n        )\n\n    def send_preamble(self):\n        &quot;&quot;&quot;Transmit version\/status\/date\/server, via self._write()&quot;&quot;&quot;\n        if self.origin_server:\n            if self.client_is_modern():\n                self._write(('HTTP\/%s %s\\r\\n' % (self.http_version,self.status)).encode('iso-8859-1'))\n                if 'Date' not in self.headers:\n                    self._write(\n                        ('Date: %s\\r\\n' % format_date_time(time.time())).encode('iso-8859-1')\n                    )\n                if self.server_software and 'Server' not in self.headers:\n                    self._write(('Server: %s\\r\\n' % self.server_software).encode('iso-8859-1'))\n        else:\n            self._write(('Status: %s\\r\\n' % self.status).encode('iso-8859-1'))\n\n    def write(self, data):\n        &quot;&quot;&quot;'write()' callable as specified by PEP 3333&quot;&quot;&quot;\n\n        assert type(data) is bytes, \\\n            &quot;write() argument must be a bytes instance&quot;\n\n        if not self.status:\n            raise AssertionError(&quot;write() before start_response()&quot;)\n\n        elif not self.headers_sent:\n            # Before the first output, send the stored headers\n            self.bytes_sent = len(data)    # make sure we know content-length\n            self.send_headers()\n        else:\n            self.bytes_sent += len(data)\n\n        # XXX check Content-Length and truncate if too many bytes written?\n        self._write(data)\n        self._flush()\n\n    def sendfile(self):\n        &quot;&quot;&quot;Platform-specific file transmission\n\n        Override this method in subclasses to support platform-specific\n        file transmission.  It is only called if the application's\n        return iterable ('self.result') is an instance of\n        'self.wsgi_file_wrapper'.\n\n        This method should return a true value if it was able to actually\n        transmit the wrapped file-like object using a platform-specific\n        approach.  It should return a false value if normal iteration\n        should be used instead.  An exception can be raised to indicate\n        that transmission was attempted, but failed.\n\n        NOTE: this method should call 'self.send_headers()' if\n        'self.headers_sent' is false and it is going to attempt direct\n        transmission of the file.\n        &quot;&quot;&quot;\n        return False   # No platform-specific transmission by default\n\n    def finish_content(self):\n        &quot;&quot;&quot;Ensure headers and content have both been sent&quot;&quot;&quot;\n        if not self.headers_sent:\n            # Only zero Content-Length if not set by the application (so\n            # that HEAD requests can be satisfied properly, see #3839)\n            self.headers.setdefault('Content-Length', &quot;0&quot;)\n            self.send_headers()\n        else:\n            pass # XXX check if content-length was too short?\n\n    def close(self):\n        &quot;&quot;&quot;Close the iterable (if needed) and reset all instance vars\n\n        Subclasses may want to also drop the client connection.\n        &quot;&quot;&quot;\n        try:\n            if hasattr(self.result,'close'):\n                self.result.close()\n        finally:\n            self.result = self.headers = self.status = self.environ = None\n            self.bytes_sent = 0; self.headers_sent = False\n\n    def send_headers(self):\n        &quot;&quot;&quot;Transmit headers to the client, via self._write()&quot;&quot;&quot;\n        self.cleanup_headers()\n        self.headers_sent = True\n        if not self.origin_server or self.client_is_modern():\n            self.send_preamble()\n            self._write(bytes(self.headers))\n\n    def result_is_file(self):\n        &quot;&quot;&quot;True if 'self.result' is an instance of 'self.wsgi_file_wrapper'&quot;&quot;&quot;\n        wrapper = self.wsgi_file_wrapper\n        return wrapper is not None and isinstance(self.result,wrapper)\n\n    def client_is_modern(self):\n        &quot;&quot;&quot;True if client can accept status and headers&quot;&quot;&quot;\n        return self.environ['SERVER_PROTOCOL'].upper() != 'HTTP\/0.9'\n\n    def log_exception(self,exc_info):\n        &quot;&quot;&quot;Log the 'exc_info' tuple in the server log\n\n        Subclasses may override to retarget the output or change its format.\n        &quot;&quot;&quot;\n        try:\n            from traceback import print_exception\n            stderr = self.get_stderr()\n            print_exception(\n                exc_info[0], exc_info[1], exc_info[2],\n                self.traceback_limit, stderr\n            )\n            stderr.flush()\n        finally:\n            exc_info = None\n\n    def handle_error(self):\n        &quot;&quot;&quot;Log current error, and send error output to client if possible&quot;&quot;&quot;\n        self.log_exception(sys.exc_info())\n        if not self.headers_sent:\n            self.result = self.error_output(self.environ, self.start_response)\n            self.finish_response()\n        # XXX else: attempt advanced recovery techniques for HTML or text?\n\n    def error_output(self, environ, start_response):\n        &quot;&quot;&quot;WSGI mini-app to create error output\n\n        By default, this just uses the 'error_status', 'error_headers',\n        and 'error_body' attributes to generate an output page.  It can\n        be overridden in a subclass to dynamically generate diagnostics,\n        choose an appropriate message for the user's preferred language, etc.\n\n        Note, however, that it's not recommended from a security perspective to\n        spit out diagnostics to any old user; ideally, you should have to do\n        something special to enable diagnostic output, which is why we don't\n        include any here!\n        &quot;&quot;&quot;\n        start_response(self.error_status,self.error_headers[:],sys.exc_info())\n        return [self.error_body]\n\n    # Pure abstract methods; *must* be overridden in subclasses\n\n    def _write(self,data):\n        &quot;&quot;&quot;Override in subclass to buffer data for send to client\n\n        It's okay if this method actually transmits the data; BaseHandler\n        just separates write and flush operations for greater efficiency\n        when the underlying system actually has such a distinction.\n        &quot;&quot;&quot;\n        raise NotImplementedError\n\n    def _flush(self):\n        &quot;&quot;&quot;Override in subclass to force sending of recent '_write()' calls\n\n        It's okay if this method is a no-op (i.e., if '_write()' actually\n        sends the data.\n        &quot;&quot;&quot;\n        raise NotImplementedError\n\n    def get_stdin(self):\n        &quot;&quot;&quot;Override in subclass to return suitable 'wsgi.input'&quot;&quot;&quot;\n        raise NotImplementedError\n\n    def get_stderr(self):\n        &quot;&quot;&quot;Override in subclass to return suitable 'wsgi.errors'&quot;&quot;&quot;\n        raise NotImplementedError\n\n    def add_cgi_vars(self):\n        &quot;&quot;&quot;Override in subclass to insert CGI variables in 'self.environ'&quot;&quot;&quot;\n        raise NotImplementedError<\/code><\/pre>\n<p>\u6211\u4eec\u628arun()\u65b9\u6cd5\u62ff\u51fa\u6765<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseHandler:\n    ...\n    def run(self, application):\n        &quot;&quot;&quot;Invoke the application&quot;&quot;&quot;\n        # Note to self: don't move the close()!  Asynchronous servers shouldn't\n        # call close() from finish_response(), so if you close() anywhere but\n        # the double-error branch here, you'll break asynchronous servers by\n        # prematurely closing.  Async servers must return from 'run()' without\n        # closing if there might still be output to iterate over.\n        try:\n            self.setup_environ()\n            self.result = application(self.environ, self.start_response)\n            self.finish_response()\n        except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):\n            # We expect the client to close the connection abruptly from time\n            # to time.\n            return\n        except:\n            try:\n                self.handle_error()\n            except:\n                # If we get an error handling an error, just give up already!\n                self.close()\n                raise   # ...and let the actual server figure it out.<\/code><\/pre>\n<p>\u5173\u952e\u4ee3\u7801<\/p>\n<pre><code class=\"lang-python language-python python\">try:\n    self.setup_environ()\n    self.result = application(self.environ, self.start_response)\n    self.finish_response()<\/code><\/pre>\n<ul>\n<li>self.setup_environ()\u521d\u59cb\u5316\u76f8\u5173\u73af\u5883\u4fe1\u606f,\u5177\u4f53\u53ef\u4ee5\u6839\u636e\u540c\u6837\u601d\u8def\u67e5\u770b\u600e\u4e48\u521d\u59cb\u5316\u53ca\u6709\u54ea\u4e9b\u4fe1\u606f\u8fdb\u884c\u4e86\u521d\u59cb\u5316<\/li>\n<li>\u8c03\u7528\u4e86application\u5e94\u7528,\u8fd9\u4e2a\u5e94\u7528\u5c31\u662f\u6700\u5916\u5c42\u4e3b\u51fd\u6570\u6211\u4eec\u5b9a\u4e49\u7684application\u5e94\u7528\u3002\u4f20\u9012\u7684\u662fWSGIRequestHandler\u7c7b\u5bf9\u8c61\u7684\u6570\u636e\u3002<\/li>\n<li>\u6700\u540e\u8c03\u7528\u4e86self.finish_response()<\/li>\n<\/ul>\n<p>\u73b0\u5728\u6211\u4eec\u641e\u6e05 self.environ, self.start_response\u4ece\u54ea\u91cc\u6765\u7684\u3002\n\u5728\u4e0a\u9762run()\u65b9\u6cd5\u4e2d\u7684try\u9996\u5148\u8c03\u7528\u4e86self.setup_environ()\n<strong><em>(1)self.environ\u6765\u6e90<\/em><\/strong><\/p>\n<pre><code class=\"lang-python language-python python\">    def setup_environ(self):\n        &quot;&quot;&quot;Set up the environment for one request&quot;&quot;&quot;\n\n        env = self.environ = self.os_environ.copy()\n        self.add_cgi_vars()\n\n        env['wsgi.input']        = self.get_stdin()\n        env['wsgi.errors']       = self.get_stderr()\n        env['wsgi.version']      = self.wsgi_version\n        env['wsgi.run_once']     = self.wsgi_run_once\n        env['wsgi.url_scheme']   = self.get_scheme()\n        env['wsgi.multithread']  = self.wsgi_multithread\n        env['wsgi.multiprocess'] = self.wsgi_multiprocess\n\n        if self.wsgi_file_wrapper is not None:\n            env['wsgi.file_wrapper'] = self.wsgi_file_wrapper\n\n        if self.origin_server and self.server_software:\n            env.setdefault('SERVER_SOFTWARE',self.server_software)<\/code><\/pre>\n<p>\u5176\u4e2d\u6709self.environ = self.os_environ.copy(),\u5728BaseHandler\u7c7b\u4e2d\u6709\u5b9a\u4e49\nos_environ= read_environ()\n\u6211\u4eec\u518d\u627e\u5230read_environ\u51fd\u6570\u7684\u5b9a\u4e49<\/p>\n<pre><code class=\"lang-python language-python python\">def read_environ():\n    &quot;&quot;&quot;Read environment, fixing HTTP variables&quot;&quot;&quot;\n    enc = sys.getfilesystemencoding()\n    esc = 'surrogateescape'\n    try:\n        ''.encode('utf-8', esc)\n    except LookupError:\n        esc = 'replace'\n    environ = {}\n\n    # Take the basic environment from native-unicode os.environ. Attempt to\n    # fix up the variables that come from the HTTP request to compensate for\n    # the bytes-&gt;unicode decoding step that will already have taken place.\n    for k, v in os.environ.items():\n        if _needs_transcode(k):\n\n            # On win32, the os.environ is natively Unicode. Different servers\n            # decode the request bytes using different encodings.\n            if sys.platform == 'win32':\n                software = os.environ.get('SERVER_SOFTWARE', '').lower()\n\n                # On IIS, the HTTP request will be decoded as UTF-8 as long\n                # as the input is a valid UTF-8 sequence. Otherwise it is\n                # decoded using the system code page (mbcs), with no way to\n                # detect this has happened. Because UTF-8 is the more likely\n                # encoding, and mbcs is inherently unreliable (an mbcs string\n                # that happens to be valid UTF-8 will not be decoded as mbcs)\n                # always recreate the original bytes as UTF-8.\n                if software.startswith('microsoft-iis\/'):\n                    v = v.encode('utf-8').decode('iso-8859-1')\n\n                # Apache mod_cgi writes bytes-as-unicode (as if ISO-8859-1) direct\n                # to the Unicode environ. No modification needed.\n                elif software.startswith('apache\/'):\n                    pass\n\n                # Python 3's http.server.CGIHTTPRequestHandler decodes\n                # using the urllib.unquote default of UTF-8, amongst other\n                # issues.\n                elif (\n                    software.startswith('simplehttp\/')\n                    and 'python\/3' in software\n                ):\n                    v = v.encode('utf-8').decode('iso-8859-1')\n\n                # For other servers, guess that they have written bytes to\n                # the environ using stdio byte-oriented interfaces, ending up\n                # with the system code page.\n                else:\n                    v = v.encode(enc, 'replace').decode('iso-8859-1')\n\n            # Recover bytes from unicode environ, using surrogate escapes\n            # where available (Python 3.1+).\n            else:\n                v = v.encode(enc, esc).decode('iso-8859-1')\n\n        environ[k] = v\n    return environ<\/code><\/pre>\n<p>\u8fd9\u6bb5\u4ee3\u7801\u6838\u5fc3\u4f5c\u7528\u662f\uff1a\u4ece\u64cd\u4f5c\u7cfb\u7edf\u7684\u5168\u5c40\u73af\u5883\u53d8\u91cf\u4e2d\u8bfb\u53d6\u3001\u4fee\u590d\u5e76\u7ec4\u88c5\u51fa\u7b26\u5408 WSGI \u89c4\u8303\u7684\u57fa\u7840 environ \u5b57\u5178\u3002\u6240\u4ee5application\u4e2d\u7684environ\u662fpython\u8fdb\u7a0b\u4ece\u7cfb\u7edf\u73af\u5883\u53d8\u91cf\u4e2d\u89e3\u6790\u51fa\u6765\u7684,\u800c\u9700\u8981\u7684\u73af\u5883\u53d8\u91cf\u901a\u5e38\u662f\u6709nginx\u6216\u8005apache\u4ece\u8bf7\u6c42\u4e2d\u6e05\u6d17\u51fa\u6765\u7684,\u6240\u4ee5wsgi\u4e3a\u4f55\u9700\u8981\u7c7b\u548cnginx\u7b49\u4e2d\u95f4\u4ef6\u539f\u56e0\u3002\nWSGI\uff08\u5305\u62ec Gunicorn\/uWSGI \u7b49\u5bb9\u5668\uff09\u4e4b\u6240\u4ee5\u65e0\u6cd5\u5355\u67aa\u5339\u9a6c\u7edf\u6cbb\u4e16\u754c\uff0c\u5fc5\u987b\u8981\u548c Nginx\/Apache \u7ed3\u4e3a\u592b\u59bb\uff0c\u662f\u56e0\u4e3a\u4ee5\u4e0b 4 \u4e2a\u6781\u5176\u6b8b\u9177\u7684\u5de5\u4e1a\u7ea7\u7269\u7406\u73b0\u5b9e\uff1a<\/p>\n<h4>\u539f\u56e0\u4e00\uff1a\u4e0a\u6e38\u534f\u8bae\u7684\u201c\u7ffb\u8bd1\u5b98\u201d\uff08\u547c\u5e94\u6e90\u7801\uff09<\/h4>\n<p>\u6b63\u5982\u5728 read_environ() \u6e90\u7801\u91cc\u770b\u5230\u7684\uff0c\u8bb8\u591a\u7ecf\u5178\u7684 Python Web \u7f51\u5173\u7a0b\u5e8f\u5728\u8bbe\u8ba1\u4e4b\u521d\uff0c\u5c31\u662f\u4e3a\u4e86\u5bf9\u63a5\u64cd\u4f5c\u7cfb\u7edf\u7684\u6807\u51c6 CGI\/FastCGI\/SCGI \u73af\u5883\u53d8\u91cf\u800c\u7f16\u5199\u7684\u3002<\/p>\n<ul>\n<li><strong><em>Nginx\/Apache \u7684\u804c\u8d23<\/em><\/strong>\uff1a\u5b83\u4eec\u64c5\u957f\u5728\u6700\u524d\u7aef\u62b5\u6321\u5168\u4e16\u754c\u7684\u6d41\u91cf\uff0c\u628a\u6210\u5343\u4e0a\u4e07\u4e2a\u6d4f\u89c8\u5668\u53d1\u6765\u7684\u539f\u59cb HTTP \u8bf7\u6c42\uff0c\u5265\u79bb\u89e3\u6790\u6210\u5e72\u51c0\u7684\u53d8\u91cf\u3001Header \u548c\u6570\u636e\u6d41\uff0c\u7136\u540e\u901a\u8fc7\u9ad8\u901f\u7ba1\u9053\u4e22\u7ed9\u540e\u7aef\u7684 WSGI\u3002<\/li>\n<li><strong><em>WSGI \u7684\u804c\u8d23<\/em><\/strong>\uff1a\u8d1f\u8d23\u63a5\u529b\uff0c\u628a\u8fd9\u4e9b\u53d8\u91cf\u65e0\u635f\u4fee\u590d\u3001\u6d17\u5e72\u51c0\u7ec4\u88c5\u6210 environ \u5b57\u5178\uff0c\u6254\u7ed9 Python \u4ee3\u7801\u3002<\/li>\n<\/ul>\n<h4>\u539f\u56e0\u4e8c\uff1a\u9759\u6001\u8d44\u6e90\u5206\u6d41\uff08Nginx \u662f\u8dd1\u8f66\u7684\u53d1\u52a8\u673a\uff0cPython \u662f\u725b\u8f66\uff09<\/h4>\n<p>\u4e00\u4e2a\u7f51\u9875\u91cc\u9664\u4e86 Python \u52a8\u6001\u7b97\u51fa\u6765\u7684\u6570\u636e\uff08\u5982\u7528\u6237\u4f59\u989d\u3001\u8ba2\u5355\uff09\uff0c\u8fd8\u5305\u542b\u5927\u91cf\u7684\u9759\u6001\u8d44\u6e90\uff08\u5982\u51e0\u767e\u5146\u7684\u56fe\u7247\u3001\u89c6\u9891\u3001CSS\u3001JavaScript\uff09\u3002<\/p>\n<ul>\n<li><strong><em>\u5982\u679c\u53ea\u7528 WSGI<\/em><\/strong>\uff1a\u6211\u4eec\u4e4b\u524d\u770b\u8fc7\uff0cWSGI \u5904\u7406\u6570\u636e\u7684\u5e95\u5c42\u662f\u8c03\u7528 for data in self.result: self.write(data) \u4e00\u5305\u4e00\u5305\u5728\u5355\u7ebf\u7a0b\/\u591a\u7ebf\u7a0b\u91cc\u78e8\u78e8\u5527\u5527\u5730\u5199\u7f51\u7edc Socket\u3002\u5982\u679c\u7528 Python \u8fdb\u78c1\u76d8\u8bfb\u56fe\u7247\u518d\u5199\u56de\u7ed9\u7f51\u5361\uff0cCPU \u548c\u5185\u5b58\u4f1a\u88ab\u8fc5\u901f\u69a8\u5e72\uff0c\u670d\u52a1\u5668\u77ac\u95f4\u53d8\u6162\u3002<\/li>\n<li><strong><em>\u914d\u5408 Nginx<\/em><\/strong>\uff1aNginx \u662f\u7528\u7eaf C \u8bed\u8a00\u5199\u7684\uff0c\u5b83\u5185\u90e8\u4f7f\u7528\u4e86\u6781\u5176\u6050\u6016\u7684\u64cd\u4f5c\u7cfb\u7edf\u5185\u6838\u7ea7\u795e\u6280 \u2014\u2014 sendfile\uff08\u96f6\u62f7\u8d1d\u6280\u672f Zero-Copy\uff09\u3002\u5f53\u6d4f\u89c8\u5668\u8bf7\u6c42\u4e00\u5f20\u56fe\u7247\u65f6\uff0cNginx \u53ef\u4ee5\u4e0d\u7ecf\u8fc7\u4efb\u4f55\u5e94\u7528\u5c42\u5185\u5b58\uff0c\u76f4\u63a5\u628a\u786c\u76d8\u6570\u636e\u5728\u5185\u6838\u6001\u201c\u7529\u201d\u7ed9\u7f51\u5361\u3002\u5176\u4f20\u8f93\u9759\u6001\u6587\u4ef6\u7684\u901f\u5ea6\u662f Python \u7684\u6570\u5341\u500d\u5230\u6570\u767e\u500d\u3002\u56e0\u6b64\uff0c\u751f\u4ea7\u73af\u5883\u7684\u6807\u51c6\u505a\u6cd5\u662f\uff1aNginx \u62e6\u622a\u6240\u6709\u9759\u6001\u6587\u4ef6\u76f4\u63a5\u8fd4\u56de\uff1b\u53ea\u6709\u9047\u5230 \/api \u8fd9\u79cd\u52a8\u6001\u8bf7\u6c42\uff0c\u624d\u8f6c\u53d1\u7ed9\u540e\u7aef\u7684 WSGI\u3002<\/li>\n<\/ul>\n<p><strong><em>(2)self.start_response\u6765\u6e90<\/em><\/strong>\n\u6211\u4eec\u5728wsgiref\u6a21\u5757\u7684handlers.py\u6587\u4ef6\u7684217\u884c\u627e\u5230\u4e86\u51fd\u6570\u5b9a\u4e49,\u5b9a\u4e49\u5728BaseHandler\u7c7b\u4e0b,\u4ee3\u7801\u5982\u4e0b:<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseHandler:\n    ...\n\n    def start_response(self, status, headers,exc_info=None):\n        &quot;&quot;&quot;'start_response()' callable as specified by PEP 3333&quot;&quot;&quot;\n\n        if exc_info:\n            try:\n                if self.headers_sent:\n                    raise\n            finally:\n                exc_info = None        # avoid dangling circular ref\n        elif self.headers is not None:\n            raise AssertionError(&quot;Headers already set!&quot;)\n\n        self.status = status\n        self.headers = self.headers_class(headers)\n        status = self._convert_string_type(status, &quot;Status&quot;)\n        self._validate_status(status)\n\n        if __debug__:\n            for name, val in headers:\n                name = self._convert_string_type(name, &quot;Header name&quot;)\n                val = self._convert_string_type(val, &quot;Header value&quot;)\n                assert not is_hop_by_hop(name),\\\n                       f&quot;Hop-by-hop header, '{name}: {val}', not allowed&quot;\n\n        return self.write<\/code><\/pre>\n<p>\u8fd9\u4e2a\u51fd\u6570\u53ef\u4ee5\u63a5\u65363\u4e2a\u53c2\u6570:\u72b6\u6001\u7801,\u8bf7\u6c42\u5934,exc_info(\u9ed8\u8ba4None)\u3002\u8fd9\u4e5f\u6620\u7167\u5f00\u5934\u6211\u4eec\u5b9a\u4e49\u7684WSGI\u5e94\u7528application\u5185\u7684start_response\u4f20\u5165\u72b6\u6001\u7801\u4e0e\u8bf7\u6c42\u5934\u3002\u6700\u7ec8\u8fd9\u4e2a\u51fd\u6570\u8fd4\u56deself.write\u3002\n\u5b83\u7684\u6838\u5fc3\u4f5c\u7528\u662f\uff1a\u5f3a\u529b\u62e6\u622a\u5e76\u4e25\u683c\u6821\u9a8c\u6846\u67b6\u5c42\u4f20\u8fc7\u6765\u7684 HTTP \u72b6\u6001\u7801\u548c\u54cd\u5e94\u5934\uff08Headers\uff09\uff0c\u786e\u4fdd\u5b83\u4eec 100% \u7b26\u5408\u4e92\u8054\u7f51 HTTP \u534f\u8bae\u89c4\u8303\u3002\n\u5173\u4e8e\u4e0a\u9762\u8fd9\u6bb5start_response\u4ee3\u7801\u90e8\u95e8\u5173\u952e\u89e3\u6790:\n\uff081)exc_info<\/p>\n<pre><code class=\"lang-python language-python python\"># \u3010\u5f02\u5e38\u5206\u652f\u3011\u5982\u679c\u4f20\u5165\u4e86\u9519\u8bef\u5806\u6808\u4fe1\u606f\uff08\u901a\u5e38\u662f\u5e94\u7528\u5c42\u5d29\u6e83\u4e86\uff0c\u60f3\u91cd\u65b0\u4fee\u6539 Headers \u53d1\u9001\u9519\u8bef\u9875\uff09\n    if exc_info:\n        try:\n            # \u5982\u679c\u670d\u52a1\u5668\u4e4b\u524d\u5df2\u7ecf\u628a\u65e7\u7684 Headers\u3010\u7269\u7406\u53d1\u9001\u3011\u7ed9\u6d4f\u89c8\u5668\u4e86\n            if self.headers_sent:\n                raise # \u7269\u7406\u4e0a\u5df2\u7ecf\u53d1\u51fa\u53bb\u4e86\uff0c\u6728\u5df2\u6210\u821f\uff0c\u65e0\u6cd5\u633d\u56de\uff0c\u76f4\u63a5 raise \u91cd\u65b0\u629b\u51fa\u5f02\u5e38\n        finally:\n            exc_info = None        # \u6e05\u7a7a\u9519\u8bef\u4fe1\u606f\uff0c\u907f\u514d\u53d1\u751f\u5783\u573e\u56de\u6536\u7684\u5faa\u73af\u5f15\u7528\uff08\u5185\u5b58\u6cc4\u6f0f\uff09<\/code><\/pre>\n<p>(2)self.headers is not None<\/p>\n<pre><code class=\"lang-python language-python python\"># \u3010\u6b63\u5e38\u5206\u652f\u3011\u5982\u679c\u5e94\u7528\u5c42\u8bd5\u56fe\u3010\u7b2c\u4e8c\u6b21\u3011\u8c03\u7528 start_response() \u4e14\u4e4b\u524d\u5df2\u7ecf\u8bbe\u7f6e\u8fc7 Headers \u4e86\n    elif self.headers is not None:\n        # \u5f3a\u884c\u629b\u51fa AssertionError \u5d29\u6e83\uff01WSGI \u89c4\u5b9a 1 \u4e2a\u8bf7\u6c42\u53ea\u80fd\u8bbe\u7f6e 1 \u6b21\u54cd\u5e94\u5934\n        raise AssertionError(&quot;Headers already set!&quot;)<\/code><\/pre>\n<p>\uff083)\u5269\u4f59\u90e8\u5206<\/p>\n<pre><code class=\"lang-python language-python python\">    # \ud83c\udf1f \u6838\u5fc3\u4ea4\u63a5\u70b9 1\uff1a\u628a\u6846\u67b6\u4f20\u8fc7\u6765\u7684\u72b6\u6001\u7801\uff08\u5982 &quot;200 OK&quot;\uff09\u548c\u54cd\u5e94\u5934\u5217\u8868\uff08Headers\uff09\u4fdd\u5b58\u5230\u670d\u52a1\u5668\u81ea\u5df1\u7684\u5c5e\u6027\u91cc\n    self.status = status\n    self.headers = self.headers_class(headers)\n\n    # \u6838\u5fc3\u4ea4\u63a5\u70b9 2\uff1a\u5f3a\u7c7b\u578b\u6821\u9a8c\u3002\u5c06\u72b6\u6001\u7801\u8f6c\u6362\u4e3a\u6807\u51c6 Python \u5b57\u7b26\u4e32\u7c7b\u578b\u5e76\u8fdb\u884c\u4e25\u5bc6\u9a8c\u8bc1\n    status = self._convert_string_type(status, &quot;Status&quot;)\n    self._validate_status(status) # \u68c0\u67e5\u72b6\u6001\u7801\u662f\u4e0d\u662f\u6807\u51c6\u7684&ldquo;3\u4f4d\u6570\u5b57 + \u63cf\u8ff0&rdquo;\uff08\u5982 200 OK\uff09\n\n    # \u3010\u8c03\u8bd5\u6a21\u5f0f\u68c0\u67e5\u3011\u5982\u679c\u662f __debug__ \u72b6\u6001\u4e0b\u8fd0\u884c\n    if __debug__:\n        # \u904d\u5386\u6846\u67b6\u4f20\u8fc7\u6765\u7684\u6bcf\u4e00\u4e2a Header \u952e\u503c\u5bf9\n        for name, val in headers:\n            name = self._convert_string_type(name, &quot;Header name&quot;)\n            val = self._convert_string_type(val, &quot;Header value&quot;)\n\n            # \ud83c\udf1f \u786c\u6838\u7f51\u7edc\u539f\u7406\u62e6\u622a\uff1a\u68c0\u67e5\u8fd9\u4e2a Header \u662f\u4e0d\u662f\u5c5e\u4e8e\u7981\u5fcc\u7684 &quot;Hop-by-hop&quot;\uff08\u9010\u8df3\uff09\u8bf7\u6c42\u5934\n            # \u5982\u679c\u662f\uff08\u5982 Connection, Keep-Alive, Transfer-Encoding\uff09\n            assert not is_hop_by_hop(name),\\\n                   f&quot;Hop-by-hop header, '{name}: {val}', not allowed&quot; # \u76f4\u63a5\u629b\u51fa\u65ad\u8a00\u9519\u8bef\u62e6\u622a\uff01\n\n    # \ud83c\udf1f \u5168\u5267\u7684\u5927\u7ec8\u7ed3\uff1a\u6700\u540e\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u628a\u670d\u52a1\u5668\u5185\u90e8\u7684 `self.write` \u51fd\u6570\u5bf9\u8c61\u4f5c\u4e3a\u8fd4\u56de\u503c\u8fd4\u56de\uff01\n    return self.write<\/code><\/pre>\n<p>\u6211\u4eec\u518d\u770b\u770b\u72b6\u6001\u7801\u6821\u9a8c\u903b\u8f91,\u5728\u627e\u5230\u5bf9\u5e94\u4ee3\u7801:<\/p>\n<pre><code class=\"lang-python language-python python\">class BaseHandler:\n    ...\n    def _validate_status(self, status):\n        if len(status) &lt; 4:\n            raise AssertionError(&quot;Status must be at least 4 characters&quot;)\n        if not status[:3].isdigit():\n            raise AssertionError(&quot;Status message must begin w\/3-digit code&quot;)\n        if status[3] != &quot; &quot;:\n            raise AssertionError(&quot;Status message must have a space after code&quot;)<\/code><\/pre>\n<p>\u6839\u636e\u4ee3\u7801\u603b\u7ed3status\u8981\u6c42:<\/p>\n<ul>\n<li>\u81f3\u5c114\u4e2a\u5b57\u7b26<\/li>\n<li>\u524d3\u4e2a\u5fc5\u987b\u662f\u6570\u5b57<\/li>\n<li>\u6570\u5b57\u540e\u9762\u9700\u8981\u7a7a\u683c<\/li>\n<\/ul>\n<p>\u6240\u4ee5\u5728start_response\u91cc\u5b9a\u4e49\u7684status\u5fc5\u987b\u7b26\u5408\u8fd93\u4e2a\u8981\u6c42,\u5426\u5219\u4e0d\u901a\u8fc7,\u6211\u4eec\u5728\u5f00\u5934\u5f15\u4f8b\u4e2d\u4e5f\u90fd\u662f\u8fd9\u6837\u5b9a\u4e49\u7684\u3002<\/p>\n<p><strong><em>\u5728run()\u65b9\u6cd5\u4e2d,\u8c03\u7528application\u540e\u63a5\u7740\u5c31\u8c03\u7528\u4e86self.finish_response()\u51fd\u6570<\/em><\/strong>,\u76f8\u5173\u4ee3\u7801:<\/p>\n<pre><code class=\"lang-python language-python python\">try:\n    self.setup_environ()\n    self.result = application(self.environ, self.start_response)\n    self.finish_response()<\/code><\/pre>\n<p>\u63a5\u4e0b\u6765\u770b\u770bfinish_response\u51fd\u6570\u5e72\u4e86\u4ec0\u4e48\u3002<\/p>\n<pre><code class=\"lang-python language-python python\">    def finish_response(self):\n    &quot;&quot;&quot;\u53d1\u9001\u6240\u6709\u53ef\u8fed\u4ee3\u7684\u6570\u636e\uff0c\u7136\u540e\u5173\u95ed\u81ea\u8eab\u4ee5\u53ca\u8be5\u53ef\u8fed\u4ee3\u5bf9\u8c61&quot;&quot;&quot;\n    # \u3010\u8bbe\u8ba1\u6587\u6863\u63d0\u793a\u3011\uff1a\u5982\u679c\u662f\u7528\u4e8e\u5f02\u6b65\u670d\u52a1\u5668\uff08Asynchronous servers\uff09\u7684\u5b50\u7c7b\uff0c\n    # \u9700\u8981\u91cd\u5199\u8fd9\u4e2a\u65b9\u6cd5\uff0c\u4f7f\u5176\u5728\u4e8b\u4ef6\u5faa\u73af\uff08Event Loop\uff09\u4e2d\u8bbe\u7f6e\u56de\u8c03\u6765\u8fed\u4ee3\u6570\u636e\uff0c\u5e76\u5728\u5b8c\u6210\u540e\u8c03\u7528 close()\u3002\n\n    try:\n        # \ud83c\udf1f \u4f18\u5316\u7b56\u7565\uff1a\u9996\u5148\u68c0\u67e5\u4f60\u7684\u4e1a\u52a1\u8fd4\u56de\uff08self.result\uff09\u662f\u4e0d\u662f\u4e00\u4e2a\u6587\u4ef6\u5bf9\u8c61\uff0c\u5982\u679c\u662f\uff0c\u4e14\u64cd\u4f5c\u7cfb\u7edf\u652f\u6301 sendfile \u96f6\u62f7\u8d1d\n        if not self.result_is_file() or not self.sendfile():\n\n            # \ud83c\udf1f \u5168\u5267\u6700\u9ad8\u6f6e\u7684\u7269\u7406\u53d1\u5c04\uff1a\u5982\u679c\u4e0d\u662f\u6587\u4ef6\uff0c\u6216\u8005\u4e0d\u652f\u6301\u96f6\u62f7\u8d1d\uff0c\u91c7\u7528\u6807\u51c6\u7684\u8fed\u4ee3\u5668\u6a21\u5f0f\n            # \u8fd9\u91cc\u7684 self.result \u5c31\u662f\u4f60\u7684 Flask\/Django \u6216\u4e2d\u95f4\u4ef6 return \u7684\u90a3\u4e2a\u5217\u8868\uff08\u5982 [b&quot;Hello World&quot;]\uff09\n            for data in self.result:\n                # \u8c03\u7528\u5e95\u5c42\u7684 write \u65b9\u6cd5\uff0c\u628a\u8fd9\u4e00\u4e2a\u4e2a\u5c0f\u5b57\u8282\u5305\u7269\u7406\u5199\u5165 Socket \u7f13\u51b2\u533a\uff0c\u53d1\u7ed9\u6d4f\u89c8\u5668\n                self.write(data)\n\n            # \u53d1\u9001\u5b8c\u6bd5\uff0c\u901a\u77e5\u5e95\u5c42&ldquo;\u5185\u5bb9\u53d1\u9001\u7ed3\u675f&rdquo;\uff0c\u7528\u4e8e\u8ffd\u52a0\u7ed3\u675f\u7b26\u6216\u5237\u65b0\u7f13\u51b2\u533a\n            self.finish_content()\n    except:\n        # \u3010\u5f02\u5e38\u5206\u652f\u3011\uff1a\u5982\u679c\u5728\u5411\u6d4f\u89c8\u5668\u75af\u72c2\u5199\u6570\u636e\u7684\u8fc7\u7a0b\u4e2d\u53d1\u751f\u4e86\u4efb\u4f55\u5d29\u6e83\uff08\u6bd4\u5982\u7528\u6237\u7a81\u7136\u628a\u6d4f\u89c8\u5668\u5173\u4e86\uff09\n        # \u68c0\u67e5\u4f60\u7684\u5e94\u7528\u8fd4\u56de\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08self.result\uff09\u8eab\u4e0a\u6709\u6ca1\u6709\u81ea\u5e26 close() \u65b9\u6cd5\uff08\u6bd4\u5982\u67d0\u4e9b\u957f\u8fde\u63a5\u6216\u751f\u6210\u5668\uff09\n        if hasattr(self.result, 'close'):\n            # \u5f3a\u884c\u89e6\u53d1\u5b83\u81ea\u5df1\u7684 close()\uff0c\u786e\u4fdd\u5e94\u7528\u5c42\u5185\u90e8\u7684\u8d44\u6e90\uff08\u5982\u672a\u5173\u95ed\u7684\u6570\u636e\u5e93\u8fde\u63a5\u3001\u6587\u4ef6\u53e5\u67c4\uff09\u4e0d\u4f1a\u6cc4\u6f0f\n            self.result.close()\n        # \u7ee7\u7eed\u5411\u5916\u5c42\u629b\u51fa\u5f02\u5e38\uff0c\u8ba9\u4e3b\u670d\u52a1\u5668\u53bb\u8bb0\u5f55\u9519\u8bef\u65e5\u5fd7\n        raise\n    else:\n        # \u3010\u6210\u529f\u5206\u652f\u3011\uff1a\u53ea\u6709\u5728\u6ca1\u6709\u4efb\u4f55\u5f02\u5e38\u3001\u6570\u636e\u5b8c\u7f8e\u5168\u90e8\u53d1\u9001\u7ed9\u6d4f\u89c8\u5668\u7684\u60c5\u51b5\u4e0b\uff0c\u624d\u6267\u884c else\n        # \ud83c\udf1f \u6838\u5fc3\u6536\u5c3e\uff1a\u5173\u95ed\u5f53\u524d\u7684\u5904\u7406\u5668\u5b9e\u4f8b\u3002\u5b83\u5185\u90e8\u4f1a\u628a\u72b6\u6001\u7801\u3001\u8fd4\u56de\u7ed3\u679c\u3001Headers \u548c environ \u5b57\u5178\u5168\u90e8\u6e05\u7a7a\u5e76\u8bbe\u4e3a None\n        # \u8054\u52a8\u5386\u53f2 Bug \u8865\u4e01\uff08bpo-29183\uff09\uff1a\u7edd\u5bf9\u4e0d\u80fd\u5728\u5f02\u5e38\u65f6\u63d0\u524d\u8c03\u5b83\uff0c\u5426\u5219\u4f1a\u5f15\u53d1\u5c5e\u6027\u63d0\u524d\u88ab\u62b9\u9664\u7684\u6b21\u751f\u707e\u96be\n        self.close()\n<\/code><\/pre>\n<p>\u8fd9\u6bb5\u4ee3\u7801\u5c31\u662f\u901a\u8fc7socket\u5c06\u6570\u636e\u8fd4\u56de\u7ed9\u6d4f\u89c8\u5668\u3002\n\u5173\u4e8eself.result:<\/p>\n<ul>\n<li>\n<p>\u5728run()\u65b9\u6cd5\u4e2d\u6709\u5b9a\u4e49,\u8fd9\u4e2a\u5c31\u662fapplication\u5e94\u7528\u8fd4\u56de\u7684\u7ed3\u679c,application\u5fc5\u987b\u8981\u6709\u8fd4\u56de\u503c,\u5173\u8054\u4ee3\u7801\u6bb5\u5982\u4e0b:<\/p>\n<pre><code class=\"lang-python language-python python\">   self.result = application(self.environ, self.start_response)<\/code><\/pre>\n<\/li>\n<li>\u5fc5\u987b\u662f\u4e00\u4e2a\u5217\u8868<\/li>\n<li>\u5982\u679c\u4e0d\u662f\u5217\u8868,finish_response\u4f1a\u6267\u884c\u5931\u8d25,\u5173\u8054\u4ee3\u7801\u6bb5\u5982\u4e0b:\n<pre><code class=\"lang-python language-python python\">   for data in self.result:\n      # \u8c03\u7528\u5e95\u5c42\u7684 write \u65b9\u6cd5\uff0c\u628a\u8fd9\u4e00\u4e2a\u4e2a\u5c0f\u5b57\u8282\u5305\u7269\u7406\u5199\u5165 Socket \u7f13\u51b2\u533a\uff0c\u53d1\u7ed9\u6d4f\u89c8\u5668\n      self.write(data)<\/code><\/pre>\n<hr \/>\n<h2>\u603b\u7ed3<\/h2>\n<p>\u6211\u4eec\u7406\u6e05\u7684\u7ee7\u627f\u5173\u7cfb:\n<strong><em>WSGIServer\u7c7b<\/em><\/strong>\nWSGIServer-&gt;HTTPServer-&gt;socketserver.TCPServer-&gt;BaseServer\n<strong><em>WSGIRequestHandler\u7c7b<\/em><\/strong>\nWSGIRequestHandler-&gt;BaseHTTPRequestHandler-&gt;socketserver.StreamRequestHandler-&gt;BaseRequestHandler<\/p><\/li>\n<\/ul>\n<p><strong><em>1.server\u5bf9\u8c61\u7531WSGIServer\u7c7b\u521b\u5efa,\u5e95\u5c42\u901a\u8fc7\u7ee7\u627f\u7684TCPServer\u7c7b\u521d\u59cb\u5316\u3002<\/em><\/strong><\/p>\n<pre><code>```python\nclass TCPServer(BaseServer):\n    ...\n    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):\n        &quot;&quot;&quot;Constructor.  May be extended, do not override.&quot;&quot;&quot;\n        BaseServer.__init__(self, server_address, RequestHandlerClass)\n        self.socket = socket.socket(self.address_family,\n                                    self.socket_type)\n        if bind_and_activate:\n            try:\n                self.server_bind()\n                self.server_activate()\n            except:\n                self.server_close()\n                raise\n```<\/code><\/pre>\n<ul>\n<li>TCPServer\u7c7b\u521d\u59cb\u5316\u8c03\u7528\u4e86\u57fa\u7c7b\u521d\u59cb\u5316\u5bf9\u8c61\u7684self.server_address,self.RequestHandlerClass\u3002<\/li>\n<li>\u540c\u65f6\u901a\u8fc7socket\u6a21\u5757\u521d\u59cb\u5316\u4e86socket\u5c5e\u6027\u3002<\/li>\n<li>\u6839\u636e\u4f20\u5165\u7684\u5730\u5740\u5f00\u542fsocket\u76d1\u542c\u3002<\/li>\n<\/ul>\n<p><strong><em>2.\u5c06 WSGI\u5e94\u7528application\u6ce8\u518c\u5230server\u5bf9\u8c61\u3002<\/em><\/strong>\n\u5728make_server\u51fd\u6570\u91ccserver.set_app(app)\u6ce8\u518capplication\u5e94\u7528\u5230server\u5bf9\u8c61\u3002<\/p>\n<pre><code class=\"lang-python language-python python\">     server = make_server('127.0.0.1', 8000,application)<\/code><\/pre>\n<p>\u6240\u4ee5\u5f15\u4f8b\u4e2d\u4e0a\u8ff0\u4ee3\u7801\u4f5c\u7528\u662f:<\/p>\n<ul>\n<li>\u5b9e\u4f8b\u5316WSGIServer\u7c7b\u5bf9\u8c61<\/li>\n<li>\u6839\u636e\u5730\u5740\u5f00\u542fsocket\u76d1\u542c<\/li>\n<li>\u5c06\u5b9a\u4e49\u7684application\u5e94\u7528\u6ce8\u518c\u5230\u5b9e\u4f8b\u5316WSGIServer\u7c7b\u5bf9\u8c61\u4e2d<\/li>\n<\/ul>\n<p><strong><em>3.\u8c03\u7528\u5b9e\u4f8b\u5316\u5bf9\u8c61server\u7684serve_forever()\u65b9\u6cd5<\/em><\/strong><\/p>\n<ul>\n<li>\n<p>(1)serve_forever\u8c03\u7528self._handle_request_noblock()\u65b9\u6cd5\n<strong><em>\u5728_handle_request_noblock()\u65b9\u6cd5\u5185<\/em><\/strong>\na. \u8c03\u7528socketserver.TCPServer\u7c7b\u4e2d\u5b9a\u4e49\u7684get_request()\u65b9\u6cd5\u83b7\u53d6request\u4e0eclient_address<\/p>\n<pre><code class=\"lang-python language-python python\">request, client_address = self.get_request()<\/code><\/pre>\n<p>\u5173\u8054\u7684get_request()\u65b9\u6cd5\u5b9a\u4e49:<\/p>\n<pre><code class=\"lang-python language-python python\">    def get_request(self):\n        &quot;&quot;&quot;Get the request and client address from the socket.\n\n        May be overridden.\n\n        &quot;&quot;&quot;\n        return self.socket.accept()<\/code><\/pre>\n<p>\u6240\u4ee5request, client_address\u662f\u4ecesocket\u4e2d\u83b7\u53d6\u7684\u3002\nb. \u7136\u540e\u8c03\u7528self.process_request(request, client_address)\u65b9\u6cd5<\/p>\n<\/li>\n<li>\n<p>(2)_handle_request_noblock\u8c03\u7528self.process_request(request, client_address)\u65b9\u6cd5\n<strong><em>\u5728process_request\u65b9\u6cd5\u5185<\/em><\/strong><\/p>\n<pre><code class=\"lang-python language-python python\">    def process_request(self, request, client_address):\n        &quot;&quot;&quot;Call finish_request.\n\n        Overridden by ForkingMixIn and ThreadingMixIn.\n\n        &quot;&quot;&quot;\n        self.finish_request(request, client_address)\n        self.shutdown_request(request)<\/code><\/pre>\n<p>\u8c03\u7528\u4e86self.finish_request(request, client_address)\u65b9\u6cd5<\/p>\n<\/li>\n<li>(3)_process_request\u8c03\u7528self.finish_request(request, client_address)\u65b9\u6cd5\n<strong><em>\u5728finish_request\u65b9\u6cd5\u5185<\/em><\/strong>\n<pre><code class=\"lang-python language-python python\">    def finish_request(self, request, client_address):\n        &quot;&quot;&quot;Finish one request by instantiating RequestHandlerClass.&quot;&quot;&quot;\n        self.RequestHandlerClass(request, client_address, self)<\/code><\/pre>\n<ul>\n<li>self.RequestHandlerClass\u5c31\u662f\u521b\u5efaserver\u5b9e\u4f8b\u65f6\u901a\u8fc7\u4f20\u9012WSGIRequestHandler\u7c7b\u3002<\/li>\n<li>request, client_address\u662f\u4ecesocket\u89e3\u6790\u51fa\u6765\u7684qing qiu\u8bf7\u6c42\u4e0e\u5730\u5740<\/li>\n<li>self\u5c31\u662fserver\u5bf9\u8c61\u672c\u8eab\u3002\n\u5230\u8fd9\u91cc\u5c31\u662f\u5b9e\u4f8b\u5316\u4e86WSGIRequestHandler\u7c7b,\u5b9e\u4f8b\u6ca1\u6709\u8d4b\u7ed9\u4efb\u4f55\u53d8\u91cf<\/li>\n<\/ul><\/li>\n<\/ul>\n<p><strong><em>4.\u5b9e\u4f8b\u5316WSGIRequestHandler\u7c7b<\/em><\/strong>\n\u6839\u636e\u4e0a\u9762\u5206\u6790,server.serve_forever()\u6700\u7ec8\u662f\u5b9e\u73b0WSGIRequestHandler\u7c7b\u7684\u5b9e\u4f8b\u5316,\u6839\u636e\u7ee7\u627f\u5173\u7cfb,\u6700\u7ec8\u662f\u57fa\u7c7bBaseRequestHandler\u5b9e\u73b0\u793a\u4f8b\u5316\u8fc7\u7a0b\n<strong><em>BaseRequestHandler\u7c7b\u521d\u59cb\u5316<\/em><\/strong><\/p>\n<pre><code class=\"lang-python language-python python\">    def __init__(self, request, client_address, server):\n        self.request = request\n        self.client_address = client_address\n        self.server = server\n        self.setup()\n        try:\n            self.handle()\n        finally:\n            self.finish()<\/code><\/pre>\n<p>\u5b9e\u4f8b\u5316\u4e863\u4e2a\u5c5e\u6027,\u63a5\u7740\u8c03\u7528\u4e86self.setup(),\u7136\u540e\u8c03\u7528\u4e86self.handle(),\u6700\u540e\u8c03\u7528\u4e86self.finish()\u3002\n(1)self.setup()\nself.setup()\u5728StreamRequestHandler\u7c7b\u4e2d\u5b9a\u4e49<\/p>\n<pre><code class=\"lang-python language-python python\">    def setup(self):\n        self.connection = self.request\n        if self.timeout is not None:\n            self.connection.settimeout(self.timeout)\n        if self.disable_nagle_algorithm:\n            self.connection.setsockopt(socket.IPPROTO_TCP,\n                                       socket.TCP_NODELAY, True)\n        self.rfile = self.connection.makefile('rb', self.rbufsize)\n        if self.wbufsize == 0:\n            self.wfile = _SocketWriter(self.connection)\n        else:\n            self.wfile = self.connection.makefile('wb', self.wbufsize)<\/code><\/pre>\n<p>\u8fd9\u6bb5\u4ee3\u7801\u5c06\u7cfb\u7edf\u5e95\u5c42\u7f51\u7edc\u5957\u63a5\u5b57\uff08Socket\uff09\uff0c\u7269\u7406\u6539\u9020\u6210 Python \u5f00\u53d1\u8005\u6700\u719f\u6089\u3001\u6700\u597d\u7528\u7684&#8221;\u6587\u4ef6\u8bfb\u5199\u5bf9\u8c61\uff08Stream\uff09&#8221;<\/p>\n<ul>\n<li>\n<p><strong><em>\u8d85\u65f6\u5b89\u5168\u8bbe\u7f6e<\/em><\/strong>\n\u5982\u679c\u670d\u52a1\u5668\u914d\u7f6e\u4e86\u8d85\u65f6\u65f6\u95f4\uff08timeout\uff09\uff0c\u76f4\u63a5\u8c03\u7528\u5e95\u5c42\u63a5\u53e3 settimeout()\u3002\u53ea\u8981\u6d4f\u89c8\u5668\u8fde\u8fdb\u6765\u4e4b\u540e\u8d85\u8fc7\u56fa\u5b9a\u65f6\u95f4\u4e0d\u53d1\u6570\u636e\uff0c\u7269\u7406\u8fde\u63a5\u7acb\u523b\u88ab\u5f3a\u884c\u5207\u65ad\uff0c\u9632\u6b62\u6b7b\u94fe\u63a5\u65e0\u9650\u671f\u5361\u6b7b\u5e76\u9738\u5360\u670d\u52a1\u5668\u8d44\u6e90<\/p>\n<\/li>\n<li>\n<p><strong><em>\u7981\u6389Nagle \u7b97\u6cd5<\/em><\/strong>\n\u64cd\u4f5c\u7cfb\u7edf\u7684 TCP \u534f\u8bae\u9ed8\u8ba4\u5f00\u542f\u4e86 Nagle \u7b97\u6cd5\u3002\u8fd9\u4e2a\u7b97\u6cd5\u7684\u903b\u8f91\u662f\uff1a\u5f53\u7a0b\u5e8f\u53d1\u9001\u5f88\u5c0f\u7684\u6570\u636e\u5305\u65f6\uff0c\u7cfb\u7edf\u4e0d\u9a6c\u4e0a\u53d1\u51fa\u53bb\uff0c\u800c\u662f\u7b49\u6570\u636e\u6512\u5f97\u8db3\u591f\u591a\u3001\u6216\u8005\u7b49\u4e0a\u4e00\u4e2a\u5305\u6536\u5230 ACK \u786e\u8ba4\u540e\u518d\u53d1\uff0c\u4ee5\u6b64\u6765\u8282\u7ea6\u7f51\u7edc\u5e26\u5bbd\u3002\u5728 Web \u670d\u52a1\u5668\uff08HTTP \u534f\u8bae\uff09\u4e2d\uff0c\u6211\u4eec\u9700\u8981\u6781\u9ad8\u7684\u54cd\u5e94\u901f\u5ea6\u3002\u5982\u679c\u5f00\u542f Nagle \u7b97\u6cd5\uff0c\u7f51\u9875\u7684\u5c0f\u5b57\u7b26\uff08\u6bd4\u5982\u5c0f\u54cd\u5e94\u4f53\uff09\u5728\u4f20\u8f93\u65f6\u5c31\u4f1a\u53d1\u751f\u53ef\u6015\u7684\u5ef6\u8fdf\u3002\u5b98\u65b9\u8fd9\u91cc\u5141\u8bb8\u901a\u8fc7\u7c7b\u5c5e\u6027\u628a disable_nagle_algorithm \u8bbe\u4e3a True\uff0c\u901a\u8fc7\u5e95\u5c42\u7cfb\u7edf\u8c03\u7528\u76f4\u63a5\u5f00\u542f TCP_NODELAY\uff0c\u5f3a\u5236\u7f51\u5361\u6709\u6570\u636e\u7acb\u523b\u7ed9\u6211\u987a\u7740\u7f51\u7ebf\u98de\u8fc7\u53bb\uff0c\u5b9e\u73b0\u8d85\u4f4e\u5ef6\u8fdf\u54cd\u5e94\u3002<\/p>\n<\/li>\n<li>\n<p><strong><em>\u5c06 Socket \u53d8\u6210\u4e8c\u8fdb\u5236\u53ea\u8bfb\u6587\u4ef6<\/em><\/strong>\n\u5728\u64cd\u4f5c\u7cfb\u7edf\u4e2d\uff0cSocket \u7684\u539f\u751f\u8bfb\u53d6\u975e\u5e38\u6076\u5fc3\uff0c\u4f60\u5fc5\u987b\u624b\u5199\u7c7b\u4f3c socket.recv(1024) \u5e76\u5728\u5faa\u73af\u91cc\u81ea\u5df1\u62fc\u5b57\u8282\u3002\u5b98\u65b9\u5728\u8fd9\u91cc\u8c03\u7528\u4e86 socket.makefile(&#8216;rb&#8217;)\u3002\u8fd9\u4e2a\u5e95\u5c42\u65b9\u6cd5\u4f1a\u628a\u7269\u7406\u5957\u63a5\u5b57\u65e0\u7f1d\u5305\u88c5\u6210\u4e00\u4e2a\u6807\u51c6 Python \u7684 \u5185\u7f6e\u6587\u4ef6\u7f13\u51b2\u533a\u5bf9\u8c61(BufferedReader),\u6709\u4e86\u8fd9\u4e2a\u53d8\u8eab\uff0c\u540e\u9762\u7ee7\u627f\u5b83\u7684\u5b50\u7c7b\uff08\u4e5f\u5c31\u662f\u4f60\u4e4b\u524d\u770b\u5230\u7684 WSGIRequestHandler.handle()\uff09\u624d\u53ef\u80fd\u65e0\u6bd4\u4f18\u96c5\u5730\u5199\u4e0b\u90a3\u53e5 self.rfile.readline()\u3002\u5728\u5b83\u7684\u89c6\u89d2\u91cc\uff0c\u7f51\u7edc\u8bf7\u6c42\u5df2\u7ecf\u548c\u8bfb\u53d6\u672c\u5730\u786c\u76d8\u4e0a\u7684\u7eaf\u6587\u672c\u6587\u4ef6\u6ca1\u6709\u4efb\u4f55\u533a\u522b\u4e86\u3002<\/p>\n<\/li>\n<li>\n<p><strong><em>\u4f18\u5316\u7f51\u7edc\u56de\u5199\uff1a\u5b9a\u5236\u4e8c\u8fdb\u5236\u53ea\u5199\u6587\u4ef6 (wfile)<\/em><\/strong>\n\u5982\u679c\u7528\u6237\u8981\u6c42\u4e0d\u5f00\u542f\u4efb\u4f55\u5199\u5165\u7f13\u51b2(wbufsize == 0)\uff0c\u5b98\u65b9\u4f1a\u7528\u4e00\u4e2a\u5185\u7f6e\u7684 _SocketWriter \u5305\u88c5\u5957\u63a5\u5b57\u3002\u53ea\u8981\u4f60\u7684\u4e1a\u52a1\u4ee3\u7801\u6267\u884c wfile.write(data)\uff0c\u6570\u636e\u4f1a\u6ca1\u6709\u4efb\u4f55\u505c\u987f\uff0c\u7acb\u523b\u3001\u767e\u5206\u4e4b\u767e\u5730\u7269\u7406\u5199\u5165\u7f51\u5361\u53d1\u9001\u51fa\u53bb\u3002\u5982\u679c\u5f00\u542f\u4e86\u7f13\u51b2\u533a\uff08wbufsize &gt; 0\uff09\uff0c\u540c\u6837\u901a\u8fc7 makefile(&#8216;wb&#8217;) \u5305\u88c5\u6210\u5199\u6587\u4ef6\u6d41\u3002\u5f53\u4f60\u4e1a\u52a1\u4ee3\u7801\u56de\u5199\u7f51\u9875\u5185\u5bb9\u65f6\uff0c\u6570\u636e\u5148\u6682\u5b58\u5728\u5185\u5b58\u7f13\u51b2\u533a\u91cc\uff0c\u76f4\u5230\u7f13\u51b2\u533a\u6ee1\u4e86\u3001\u6216\u8005\u4f60\u6267\u884c\u4e86 self.wfile.flush()\uff0c\u6570\u636e\u624d\u4f1a\u88ab\u4e00\u80a1\u8111\u6253\u5305\u53d1\u8d70 \u3002\u8fd9\u6781\u5927\u51cf\u5c11\u4e86\u9891\u7e41\u64cd\u4f5c\u7f51\u5361\u7684\u7cfb\u7edf\u8c03\u7528\u5f00\u9500\uff0c\u8ba9\u7f51\u7edc\u5199\u5165\u6027\u80fd\u98d9\u5347\u3002<\/p>\n<\/li>\n<\/ul>\n<p>(2)self.handle()\nself.handle()\u5728WSGIRequestHandler\u7c7b\u4e2d\u5b9a\u4e49<\/p>\n<pre><code class=\"lang-python language-python python\">    def handle(self):\n        &quot;&quot;&quot;Handle a single HTTP request&quot;&quot;&quot;\n\n        self.raw_requestline = self.rfile.readline(65537)\n        if len(self.raw_requestline) &gt; 65536:\n            self.requestline = ''\n            self.request_version = ''\n            self.command = ''\n            self.send_error(414)\n            return\n\n        if not self.parse_request(): # An error code has been sent, just exit\n            return\n\n        handler = ServerHandler(\n            self.rfile, self.wfile, self.get_stderr(), self.get_environ(),\n            multithread=False,\n        )\n        handler.request_handler = self      # backpointer for logging\n        handler.run(self.server.get_app())<\/code><\/pre>\n<p>\u5728handle\u65b9\u6cd5\u5185\u4f7f\u7528 ServerHandler\u7c7b\u521b\u5efahandler\u793a\u4f8b,\u7136\u540e\u8c03\u7528\u4e86\u5b9e\u4f8b\u7684run()\u65b9\u6cd5,run()\u65b9\u6cd5\u4f20\u9012\u7684\u662f\u6211\u4eec\u5f15\u4f8b\u4e2d\u5b9a\u4e49\u7684application\u5e94\u7528<\/p>\n<blockquote>\n<p>self.server\u5c31\u662fserver\u5b9e\u4f8b\u5bf9\u8c61,\u8fd9\u4e2a\u5bf9\u8c61\u7684get_app()\u65b9\u6cd5\u8fd4\u56de\u7684\u5c31\u662fself.application,\u800c\u8fd9\u4e2a\u5c31\u662fmake_server\u51fd\u6570\u5185\u901a\u8fc7server\u5b9e\u4f8b\u5bf9\u8c61\u7684set_app\u65b9\u6cd5\u6ce8\u518c\u7684\n\u4e3a\u4f55\u8fd9\u91ccself.server\u5c31\u662fserver\u5b9e\u4f8b\u5bf9\u8c61?\n\u56e0\u4e3aWSGIRequestHandler\u7c7b\u521d\u59cb\u5316\u65f6\u5c06\u4f20\u5165\u7684self\u5bf9\u8c61\u8d4b\u503c\u4e3aself.server,\u800c\u4f20\u7684self\u5c31\u662fserver\u5bf9\u8c61\u3002\u6574\u4e2aBaseRequestHandler\u521d\u59cb\u5316\u6765\u6e90\u4e8eserver\u5bf9\u8c61\u7684finish_request\u65b9\u6cd5\u4e2dself.RequestHandlerClass(request, client_address, self)\u8c03\u7528,\u4f20\u9012self\u81ea\u7136\u662fserver\u5bf9\u8c61\u672c\u8eab\u3002<\/p>\n<\/blockquote>\n<p><strong><em>ServerHandler\u7684\u7ee7\u627f\u5173\u7cfb<\/em><\/strong>\nServerHandler-&gt;SimpleHandler-&gt;BaseHandler<\/p>\n<p>ServerHandler\u7c7b\u7684\u5b9e\u4f8b\u5316\u5728\u7ee7\u627f\u7c7bSimpleHandler\u4e2d\u5b9a\u4e49,run()\u65b9\u6cd5\u5b9a\u4e49\u5728\u57fa\u7c7bBaseHandler\u4e2d\u3002<\/p>\n<pre><code class=\"lang-python language-python python\">    def run(self, application):\n        &quot;&quot;&quot;Invoke the application&quot;&quot;&quot;\n        # Note to self: don't move the close()!  Asynchronous servers shouldn't\n        # call close() from finish_response(), so if you close() anywhere but\n        # the double-error branch here, you'll break asynchronous servers by\n        # prematurely closing.  Async servers must return from 'run()' without\n        # closing if there might still be output to iterate over.\n        try:\n            self.setup_environ()\n            self.result = application(self.environ, self.start_response)\n            self.finish_response()\n        except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):\n            # We expect the client to close the connection abruptly from time\n            # to time.\n            return\n        except:\n            try:\n                self.handle_error()\n            except:\n                # If we get an error handling an error, just give up already!\n                self.close()\n                raise   # ...and let the actual server figure it out.<\/code><\/pre>\n<p>\u6838\u5fc3\u4ee3\u7801\u6bb5<\/p>\n<pre><code class=\"lang-python language-python python\">try:\n    self.setup_environ()\n    self.result = application(self.environ, self.start_response)\n    self.finish_response()<\/code><\/pre>\n<ul>\n<li>\n<p>self.setup_environ()\n\u63a5\u6536\u5230 HTTP \u8bf7\u6c42\uff0c\u521d\u59cb\u5316\u5e76\u6784\u5efa WSGI \u73af\u5883\u5b57\u5178\uff08\u5373 environ \u53d8\u91cf\uff09\u3002\u5305\u62ec\u4ece\u901a\u8fc7read_environ()\u51fd\u6570(\u975e\u7c7b\u4e2d\u5b9a\u4e49)\u4ece\u7cfb\u7edf\u73af\u5883\u53d8\u91cf\u4e2d\u8bfb\u53d6\u7684\u3002<\/p>\n<\/li>\n<li>\n<p>self.result = application(self.environ, self.start_response)\n\u8fd9\u91cc\u8c03\u7528\u5f15\u4f8b\u4e2d\u5b9a\u4e49\u7684application\u5e94\u7528,self.environ\u6765\u81ea\u73af\u5883\u53d8\u91cf,self.start_response\u53ea\u8981\u5bf9\u54cd\u5e94\u8fdb\u884c\u6821\u9a8c,\u8fd9\u662f\u5b9a\u4e49\u7684\u4e00\u4e2a\u51fd\u6570\u5bf9\n\u6240\u4ee5\u5728\u4e66\u5199application\u65f6:<\/p>\n<ul>\n<li>environ\u76f4\u63a5\u4f7f\u7528<\/li>\n<li>\u89c4\u8303\u5316\u586b\u5199\u76f8\u5e94\u6570\u636e,start_response\u4f1a\u8fdb\u884c\u6821\u9a8c<\/li>\n<li>\u8fd4\u56de\u89c4\u8303\u5316\u5217\u8868\u6570\u636e<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>self.finish_response()\n\u4e0a\u9762self.result\u4f1a\u5728self.finish_response()\u7528\u5230,\u6821\u9a8c\u8fd4\u56de\u7684\u6570\u636e<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"lang-python language-python python\">    def finish_response(self):\n        &quot;&quot;&quot;Send any iterable data, then close self and the iterable\n\n        Subclasses intended for use in asynchronous servers will\n        want to redefine this method, such that it sets up callbacks\n        in the event loop to iterate over the data, and to call\n        'self.close()' once the response is finished.\n        &quot;&quot;&quot;\n        try:\n            if not self.result_is_file() or not self.sendfile():\n                for data in self.result:\n                    self.write(data)\n                self.finish_content()\n        except:\n            # Call close() on the iterable returned by the WSGI application\n            # in case of an exception.\n            if hasattr(self.result, 'close'):\n                self.result.close()\n            raise\n        else:\n            # We only call close() when no exception is raised, because it\n            # will set status, result, headers, and environ fields to None.\n            # See bpo-29183 for more details.\n            self.close()<\/code><\/pre>\n<p>\u5411\u6d4f\u89c8\u5668\u5199\u56de\u6570\u636e<\/p>\n<p>(3)self.finish()\nBaseRequestHandler\u7c7b\u521d\u59cb\u5316\u6700\u7ec8\u8fd8\u4f1a\u8c03\u7528self.finish()\n\u8fd9\u4e2a\u5b9a\u4e49\u5728StreamRequestHandler\u7c7b\u4e2d<\/p>\n<pre><code class=\"lang-python language-python python\"> def finish(self):\n        if not self.wfile.closed:\n            try:\n                self.wfile.flush()\n            except socket.error:\n                # A final socket error may have occurred here, such as\n                # the local error ECONNABORTED.\n                pass\n        self.wfile.close()\n        self.rfile.close()<\/code><\/pre>\n<p>\u8fd9\u6bb5\u4e3b\u8981\u4f5c\u7528\u662f\u4e00\u6b21 HTTP \u8bf7\u6c42\u5904\u7406\u5b8c\u6210\u540e\uff0c\u5b89\u5168\u3001\u5e72\u51c0\u5730\u5173\u95ed\u7f51\u7edc\u8fde\u63a5\u5e76\u91ca\u653e\u7cfb\u7edf\u8d44\u6e90\u3002<\/p>\n<p>\u5230\u8fd9\u91cc\u5927\u5bb6\u662f\u4e0d\u662f\u4f1a\u6709\u4e00\u4e2a\u7591\u95ee\u554a,socket\u5df2\u7ecf\u76d1\u542c\uff0c\u90a3\u5e94\u8be5\u9700\u8981\u5b9e\u65f6\u53bb\u76d1\u542c\u8bf7\u6c42\u624d\u5bf9,\u5982\u679c\u5927\u5bb6\u4ed4\u7ec6\u770b\u4e0a\u9762\u8d34\u51fa\u7684\u4ee3\u7801,\u5176\u5b9eserve_forever\u6709\u8fd9\u4e48\u4e00\u6bb5:<\/p>\n<pre><code class=\"lang-python language-python python\">    def serve_forever(self, poll_interval=0.5):\n        &quot;&quot;&quot;Handle one request at a time until shutdown.\n\n        Polls for shutdown every poll_interval seconds. Ignores\n        self.timeout. If you need to do periodic tasks, do them in\n        another thread.\n        &quot;&quot;&quot;\n        self.__is_shut_down.clear()\n        try:\n            # XXX: Consider using another file descriptor or connecting to the\n            # socket to wake this up instead of polling. Polling reduces our\n            # responsiveness to a shutdown request and wastes cpu at all other\n            # times.\n            with _ServerSelector() as selector:\n                selector.register(self, selectors.EVENT_READ)\n\n                while not self.__shutdown_request:\n                    ready = selector.select(poll_interval)\n                    # bpo-35017: shutdown() called during select(), exit immediately.\n                    if self.__shutdown_request:\n                        break\n                    if ready:\n                        self._handle_request_noblock()\n\n                    self.service_actions()\n        finally:\n            self.__shutdown_request = False\n            self.__is_shut_down.set()<\/code><\/pre>\n<p>serve_forever\u91cc\u9762\u5f00\u542f\u4e86\u4e00\u4e2awhile \u5faa\u73af,\u8fd9\u4e2a\u5728\u4e00\u76f4\u76d1\u542c\u8bf7\u6c42,\u6301\u7eed\u963b\u585e\u7b49\u5f85\u4e8b\u4ef6\u53d1\u751f \u3002selector.select(poll_interval) \u4f1a\u7b49\u5f85\u5ba2\u6237\u7aef\u8fde\u63a5\uff0c\u6700\u957f\u7b49\u5f85 poll_interval\uff08\u9ed8\u8ba4 0.5 \u79d2\uff09\u3002\u7136\u540e\u6709ready\u8bf7\u6c42\u624d\u8c03\u7528self._handle_request_noblock()\u5b9e\u73b0\u6574\u4e2a\u8bf7\u6c42\u6d41\u7a0b,\u5305\u62ec\u8c03\u7528application\u5e94\u7528\u3002<\/p>\n<pre><code class=\"lang-python language-python python\">    server.serve_forever()<\/code><\/pre>\n<p>\u6240\u4ee5\u5f15\u4f8b\u4e2d\u8fd9\u6bb5\u4ee3\u7801\u4f5c\u7528\u662f:<\/p>\n<ul>\n<li>\u5f00\u542f\u8bf7\u6c42\u76d1\u542c,\u9ed8\u8ba4\u7b49\u5f85\u5ba2\u6237\u7aef\u94fe\u63a50.5s\u3002<\/li>\n<li>\u5982\u679c\u6709ready\u8bf7\u6c42\u8c03\u7528self._handle_request_noblock()\u5b9e\u73b0\u8bf7\u6c42\u6d41\u7a0b<\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>python\u4e2dwsgi\u6e90\u7801\u89e3\u6790 WSGI\uff08Web Server Gateway Interface\uff0c\u7f51\u7edc\u670d\u52a1\u5668\u7f51\u5173\u63a5\u53e3\uff09\u662f Python Web \u5f00\u53d1\u4e2d\u6700\u6838\u5fc3\u7684&#8230;<\/p>","protected":false},"author":1,"featured_media":110,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[35],"tags":[45],"class_list":["post-122","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python","tag-python"],"_links":{"self":[{"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/posts\/122","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/comments?post=122"}],"version-history":[{"count":1,"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/posts\/122\/revisions"}],"predecessor-version":[{"id":123,"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/posts\/122\/revisions\/123"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/media\/110"}],"wp:attachment":[{"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/media?parent=122"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/categories?post=122"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudnote.cc\/index.php\/wp-json\/wp\/v2\/tags?post=122"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}