mirror of
https://github.com/fofolee/uTools-Manuals.git
synced 2025-06-08 23:14:06 +08:00
168 lines
67 KiB
HTML
168 lines
67 KiB
HTML
<div class="body" role="main"><div class="section" id="module-socketserver"><h1><span class="yiyi-st" id="yiyi-10">21.21。 <a class="reference internal" href="#module-socketserver" title="socketserver: A framework for network servers."><code class="xref py py-mod docutils literal"><span class="pre">socketserver</span></code></a> - 网络服务器框架</span></h1><p><span class="yiyi-st" id="yiyi-11"><strong>源代码:</strong> <a class="reference external" href="https://hg.python.org/cpython/file/3.5/Lib/socketserver.py">Lib / socketserver.py</a></span></p><p><span class="yiyi-st" id="yiyi-12"><a class="reference internal" href="#module-socketserver" title="socketserver: A framework for network servers."><code class="xref py py-mod docutils literal"><span class="pre">socketserver</span></code></a>模块简化了编写网络服务器的任务。</span></p><p><span class="yiyi-st" id="yiyi-13">有四个基本的具体服务器类:</span></p><dl class="class"><dt id="socketserver.TCPServer"><span class="yiyi-st" id="yiyi-14"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">TCPServer</code><span class="sig-paren">(</span><em>server_address</em>, <em>RequestHandlerClass</em>, <em>bind_and_activate=True</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-15">这使用Internet TCP协议,它在客户端和服务器之间提供连续的数据流。</span><span class="yiyi-st" id="yiyi-16">如果<em>bind_and_activate</em>为true,构造函数将自动尝试调用<a class="reference internal" href="#socketserver.BaseServer.server_bind" title="socketserver.BaseServer.server_bind"><code class="xref py py-meth docutils literal"><span class="pre">server_bind()</span></code></a>和<a class="reference internal" href="#socketserver.BaseServer.server_activate" title="socketserver.BaseServer.server_activate"><code class="xref py py-meth docutils literal"><span class="pre">server_activate()</span></code></a>。</span><span class="yiyi-st" id="yiyi-17">其他参数传递到<a class="reference internal" href="#socketserver.BaseServer" title="socketserver.BaseServer"><code class="xref py py-class docutils literal"><span class="pre">BaseServer</span></code></a>基类。</span></p></dd></dl><dl class="class"><dt id="socketserver.UDPServer"><span class="yiyi-st" id="yiyi-18"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">UDPServer</code><span class="sig-paren">(</span><em>server_address</em>, <em>RequestHandlerClass</em>, <em>bind_and_activate=True</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-19">这使用数据报,其是可能在运输中不按顺序到达或丢失的信息的离散分组。</span><span class="yiyi-st" id="yiyi-20">参数与<a class="reference internal" href="#socketserver.TCPServer" title="socketserver.TCPServer"><code class="xref py py-class docutils literal"><span class="pre">TCPServer</span></code></a>相同。</span></p></dd></dl><dl class="class"><dt id="socketserver.UnixStreamServer"><span class="yiyi-st" id="yiyi-21"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">UnixStreamServer</code><span class="sig-paren">(</span><em>server_address</em>, <em>RequestHandlerClass</em>, <em>bind_and_activate=True</em><span class="sig-paren">)</span></span></dt><dt id="socketserver.UnixDatagramServer"><span class="yiyi-st" id="yiyi-22"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">UnixDatagramServer</code><span class="sig-paren">(</span><em>server_address</em>, <em>RequestHandlerClass</em>, <em>bind_and_activate=True</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-23">这些更常用的类与TCP和UDP类类似,但使用Unix域套接字;它们在非Unix平台上不可用。</span><span class="yiyi-st" id="yiyi-24">参数与<a class="reference internal" href="#socketserver.TCPServer" title="socketserver.TCPServer"><code class="xref py py-class docutils literal"><span class="pre">TCPServer</span></code></a>相同。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-25">这四个类同时处理请求<em class="dfn"></em>;每个请求必须在下一个请求开始之前完成。</span><span class="yiyi-st" id="yiyi-26">如果每个请求需要很长时间来完成,这是不合适的,因为它需要大量的计算,或者因为它返回了很多客户端处理速度慢的数据。</span><span class="yiyi-st" id="yiyi-27">解决方案是创建一个单独的进程或线程来处理每个请求; <a class="reference internal" href="#socketserver.ForkingMixIn" title="socketserver.ForkingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ForkingMixIn</span></code></a>和<a class="reference internal" href="#socketserver.ThreadingMixIn" title="socketserver.ThreadingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ThreadingMixIn</span></code></a>混合类可以用于支持异步行为。</span></p><p><span class="yiyi-st" id="yiyi-28">创建服务器需要几个步骤。</span><span class="yiyi-st" id="yiyi-29">首先,您必须通过对<a class="reference internal" href="#socketserver.BaseRequestHandler" title="socketserver.BaseRequestHandler"><code class="xref py py-class docutils literal"><span class="pre">BaseRequestHandler</span></code></a>类进行子类化并覆盖其<a class="reference internal" href="#socketserver.BaseRequestHandler.handle" title="socketserver.BaseRequestHandler.handle"><code class="xref py py-meth docutils literal"><span class="pre">handle()</span></code></a>方法来创建请求处理程序类;此方法将处理传入请求。</span><span class="yiyi-st" id="yiyi-30">其次,您必须实例化一个服务器类,将它传递给服务器的地址和请求处理程序类。</span><span class="yiyi-st" id="yiyi-31">然后调用服务器对象的<a class="reference internal" href="#socketserver.BaseServer.handle_request" title="socketserver.BaseServer.handle_request"><code class="xref py py-meth docutils literal"><span class="pre">handle_request()</span></code></a>或<a class="reference internal" href="#socketserver.BaseServer.serve_forever" title="socketserver.BaseServer.serve_forever"><code class="xref py py-meth docutils literal"><span class="pre">serve_forever()</span></code></a>方法来处理一个或多个请求。</span><span class="yiyi-st" id="yiyi-32">最后,调用<a class="reference internal" href="#socketserver.BaseServer.server_close" title="socketserver.BaseServer.server_close"><code class="xref py py-meth docutils literal"><span class="pre">server_close()</span></code></a>关闭套接字。</span></p><p><span class="yiyi-st" id="yiyi-33">当从<a class="reference internal" href="#socketserver.ThreadingMixIn" title="socketserver.ThreadingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ThreadingMixIn</span></code></a>继承线程连接行为时,应该明确声明您希望线程在突然关闭时的行为。</span><span class="yiyi-st" id="yiyi-34"><a class="reference internal" href="#socketserver.ThreadingMixIn" title="socketserver.ThreadingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ThreadingMixIn</span></code></a>类定义了一个属性<em>daemon_threads</em>,它指示服务器是否应该等待线程终止。</span><span class="yiyi-st" id="yiyi-35">如果您希望线程自主行为,您应该明确地设置标志;默认值为<a class="reference internal" href="constants.html#False" title="False"><code class="xref py py-const docutils literal"><span class="pre">False</span></code></a>,这意味着Python不会退出,直到<a class="reference internal" href="#socketserver.ThreadingMixIn" title="socketserver.ThreadingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ThreadingMixIn</span></code></a>创建的所有线程都退出。</span></p><p><span class="yiyi-st" id="yiyi-36">服务器类具有相同的外部方法和属性,无论它们使用什么网络协议。</span></p><div class="section" id="server-creation-notes"><h2><span class="yiyi-st" id="yiyi-37">21.21.1. </span><span class="yiyi-st" id="yiyi-38">服务器创建注释</span></h2><p><span class="yiyi-st" id="yiyi-39">在继承图中有五个类,其中四个表示四种类型的同步服务器:</span></p><pre><code class="language-python"><span></span><span class="o">+------------+</span>
|
||
<span class="o">|</span> <span class="n">BaseServer</span> <span class="o">|</span>
|
||
<span class="o">+------------+</span>
|
||
<span class="o">|</span>
|
||
<span class="n">v</span>
|
||
<span class="o">+-----------+</span> <span class="o">+------------------+</span>
|
||
<span class="o">|</span> <span class="n">TCPServer</span> <span class="o">|------->|</span> <span class="n">UnixStreamServer</span> <span class="o">|</span>
|
||
<span class="o">+-----------+</span> <span class="o">+------------------+</span>
|
||
<span class="o">|</span>
|
||
<span class="n">v</span>
|
||
<span class="o">+-----------+</span> <span class="o">+--------------------+</span>
|
||
<span class="o">|</span> <span class="n">UDPServer</span> <span class="o">|------->|</span> <span class="n">UnixDatagramServer</span> <span class="o">|</span>
|
||
<span class="o">+-----------+</span> <span class="o">+--------------------+</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-40">请注意,<a class="reference internal" href="#socketserver.UnixDatagramServer" title="socketserver.UnixDatagramServer"><code class="xref py py-class docutils literal"><span class="pre">UnixDatagramServer</span></code></a>源自<a class="reference internal" href="#socketserver.UDPServer" title="socketserver.UDPServer"><code class="xref py py-class docutils literal"><span class="pre">UDPServer</span></code></a>,而不是来自<a class="reference internal" href="#socketserver.UnixStreamServer" title="socketserver.UnixStreamServer"><code class="xref py py-class docutils literal"><span class="pre">UnixStreamServer</span></code></a> - IP和Unix流服务器之间的唯一区别是地址系列只是在两个Unix服务器类中重复。</span></p><dl class="class"><dt id="socketserver.ForkingMixIn"><span class="yiyi-st" id="yiyi-41"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">ForkingMixIn</code></span></dt><dt id="socketserver.ThreadingMixIn"><span class="yiyi-st" id="yiyi-42"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">ThreadingMixIn</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-43">可以使用这些混合类创建每种类型的服务器的分叉和线程版本。</span><span class="yiyi-st" id="yiyi-44">对于实例,<a class="reference internal" href="#socketserver.ThreadingUDPServer" title="socketserver.ThreadingUDPServer"><code class="xref py py-class docutils literal"><span class="pre">ThreadingUDPServer</span></code></a>创建如下:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">ThreadingUDPServer</span><span class="p">(</span><span class="n">ThreadingMixIn</span><span class="p">,</span> <span class="n">UDPServer</span><span class="p">):</span>
|
||
<span class="k">pass</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-45">混合类是第一个,因为它覆盖了<a class="reference internal" href="#socketserver.UDPServer" title="socketserver.UDPServer"><code class="xref py py-class docutils literal"><span class="pre">UDPServer</span></code></a>中定义的方法。</span><span class="yiyi-st" id="yiyi-46">设置各种属性还会更改底层服务器机制的行为。</span></p></dd></dl><dl class="class"><dt id="socketserver.ForkingTCPServer"><span class="yiyi-st" id="yiyi-47"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">ForkingTCPServer</code></span></dt><dt id="socketserver.ForkingUDPServer"><span class="yiyi-st" id="yiyi-48"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">ForkingUDPServer</code></span></dt><dt id="socketserver.ThreadingTCPServer"><span class="yiyi-st" id="yiyi-49"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">ThreadingTCPServer</code></span></dt><dt id="socketserver.ThreadingUDPServer"><span class="yiyi-st" id="yiyi-50"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">ThreadingUDPServer</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-51">这些类是使用mix-in类预定义的。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-52">要实现服务,必须从<a class="reference internal" href="#socketserver.BaseRequestHandler" title="socketserver.BaseRequestHandler"><code class="xref py py-class docutils literal"><span class="pre">BaseRequestHandler</span></code></a>派生类并重新定义其<a class="reference internal" href="#socketserver.BaseRequestHandler.handle" title="socketserver.BaseRequestHandler.handle"><code class="xref py py-meth docutils literal"><span class="pre">handle()</span></code></a>方法。</span><span class="yiyi-st" id="yiyi-53">然后,您可以通过将其中一个服务器类与请求处理程序类组合来运行服务的各种版本。</span><span class="yiyi-st" id="yiyi-54">对于数据报或流服务,请求处理程序类必须不同。</span><span class="yiyi-st" id="yiyi-55">这可以通过使用处理程序子类<a class="reference internal" href="#socketserver.StreamRequestHandler" title="socketserver.StreamRequestHandler"><code class="xref py py-class docutils literal"><span class="pre">StreamRequestHandler</span></code></a>或<a class="reference internal" href="#socketserver.DatagramRequestHandler" title="socketserver.DatagramRequestHandler"><code class="xref py py-class docutils literal"><span class="pre">DatagramRequestHandler</span></code></a>来隐藏。</span></p><p><span class="yiyi-st" id="yiyi-56">当然,你还是要用你的头!</span><span class="yiyi-st" id="yiyi-57">对于实例,如果服务包含可以由不同请求修改的内存中的状态,则使用forking服务器没有意义,因为子进程中的修改将永远不会达到父进程中保存的初始状态,并传递给每个子进程。</span><span class="yiyi-st" id="yiyi-58">在这种情况下,您可以使用线程服务器,但您可能必须使用锁来保护共享数据的完整性。</span></p><p><span class="yiyi-st" id="yiyi-59">另一方面,如果您正在构建一个HTTP服务器,其中所有数据都存储在外部(对于实例,在文件系统中),同步类将基本上在处理一个请求时渲染服务“聋” - 这可能是如果客户端缓慢地接收其请求的所有数据,则很长时间。</span><span class="yiyi-st" id="yiyi-60">这里一个线程或分叉服务器是适当的。</span></p><p><span class="yiyi-st" id="yiyi-61">在一些情况下,可能适合于同步地处理请求的一部分,但是取决于请求数据而在分叉的孩子中完成处理。</span><span class="yiyi-st" id="yiyi-62">这可以通过使用同步服务器并在请求处理程序类<a class="reference internal" href="#socketserver.BaseRequestHandler.handle" title="socketserver.BaseRequestHandler.handle"><code class="xref py py-meth docutils literal"><span class="pre">handle()</span></code></a>中执行显式fork来实现。</span></p><p><span class="yiyi-st" id="yiyi-63">在既不支持线程也不支持<a class="reference internal" href="os.html#os.fork" title="os.fork"><code class="xref py py-func docutils literal"><span class="pre">fork()</span></code></a>(或者这些对于服务来说太贵或不适用的环境)中处理多个同时请求的另一种方法是维护部分完成的请求的显式表,使用<a class="reference internal" href="selectors.html#module-selectors" title="selectors: High-level I/O multiplexing."><code class="xref py py-mod docutils literal"><span class="pre">selectors</span></code></a>来决定下一个要处理的请求(或是否处理新的传入请求)。</span><span class="yiyi-st" id="yiyi-64">这对于每个客户端可能长时间连接(如果线程或子进程不能使用)的流服务特别重要。</span><span class="yiyi-st" id="yiyi-65">有关管理此操作的另一种方法,请参见<a class="reference internal" href="asyncore.html#module-asyncore" title="asyncore: A base class for developing asynchronous socket handling services."><code class="xref py py-mod docutils literal"><span class="pre">asyncore</span></code></a>。</span></p></div><div class="section" id="server-objects"><h2><span class="yiyi-st" id="yiyi-66">21.21.2. </span><span class="yiyi-st" id="yiyi-67">服务器对象</span></h2><dl class="class"><dt id="socketserver.BaseServer"><span class="yiyi-st" id="yiyi-68"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">BaseServer</code><span class="sig-paren">(</span><em>server_address</em>, <em>RequestHandlerClass</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-69">这是模块中所有服务器对象的超类。</span><span class="yiyi-st" id="yiyi-70">它定义了接口,如下所示,但不实现大多数方法,这是在子类中完成的。</span><span class="yiyi-st" id="yiyi-71">这两个参数存储在相应的<a class="reference internal" href="#socketserver.BaseServer.server_address" title="socketserver.BaseServer.server_address"><code class="xref py py-attr docutils literal"><span class="pre">server_address</span></code></a>和<a class="reference internal" href="#socketserver.BaseServer.RequestHandlerClass" title="socketserver.BaseServer.RequestHandlerClass"><code class="xref py py-attr docutils literal"><span class="pre">RequestHandlerClass</span></code></a>属性中。</span></p><dl class="method"><dt id="socketserver.BaseServer.fileno"><span class="yiyi-st" id="yiyi-72"> <code class="descname">fileno</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-73">返回整数文件描述服务器正在侦听的套接字的器件。</span><span class="yiyi-st" id="yiyi-74">此函数最常传递到<a class="reference internal" href="selectors.html#module-selectors" title="selectors: High-level I/O multiplexing."><code class="xref py py-mod docutils literal"><span class="pre">selectors</span></code></a>,以允许在同一进程中监视多个服务器。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseServer.handle_request"><span class="yiyi-st" id="yiyi-75"> <code class="descname">handle_request</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-76">处理单个请求。</span><span class="yiyi-st" id="yiyi-77">This function calls the following methods in order: <a class="reference internal" href="#socketserver.BaseServer.get_request" title="socketserver.BaseServer.get_request"><code class="xref py py-meth docutils literal"><span class="pre">get_request()</span></code></a>, <a class="reference internal" href="#socketserver.BaseServer.verify_request" title="socketserver.BaseServer.verify_request"><code class="xref py py-meth docutils literal"><span class="pre">verify_request()</span></code></a>, and <a class="reference internal" href="#socketserver.BaseServer.process_request" title="socketserver.BaseServer.process_request"><code class="xref py py-meth docutils literal"><span class="pre">process_request()</span></code></a>. </span><span class="yiyi-st" id="yiyi-78">如果用户提供的<a class="reference internal" href="#socketserver.BaseRequestHandler.handle" title="socketserver.BaseRequestHandler.handle"><code class="xref py py-meth docutils literal"><span class="pre">handle()</span></code></a>方法的处理程序类引发异常,服务器的<a class="reference internal" href="#socketserver.BaseServer.handle_error" title="socketserver.BaseServer.handle_error"><code class="xref py py-meth docutils literal"><span class="pre">handle_error()</span></code></a>方法将被调用。</span><span class="yiyi-st" id="yiyi-79">如果在<a class="reference internal" href="#socketserver.BaseServer.timeout" title="socketserver.BaseServer.timeout"><code class="xref py py-attr docutils literal"><span class="pre">timeout</span></code></a>秒内没有收到请求,则<a class="reference internal" href="#socketserver.BaseServer.handle_timeout" title="socketserver.BaseServer.handle_timeout"><code class="xref py py-meth docutils literal"><span class="pre">handle_timeout()</span></code></a>将被调用,<a class="reference internal" href="#socketserver.BaseServer.handle_request" title="socketserver.BaseServer.handle_request"><code class="xref py py-meth docutils literal"><span class="pre">handle_request()</span></code></a>将返回。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseServer.serve_forever"><span class="yiyi-st" id="yiyi-80"> <code class="descname">serve_forever</code><span class="sig-paren">(</span><em>poll_interval=0.5</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-81">处理请求,直到显式<a class="reference internal" href="#socketserver.BaseServer.shutdown" title="socketserver.BaseServer.shutdown"><code class="xref py py-meth docutils literal"><span class="pre">shutdown()</span></code></a>请求。</span><span class="yiyi-st" id="yiyi-82">每<em>poll_interval</em>秒关闭投票。</span><span class="yiyi-st" id="yiyi-83">忽略<a class="reference internal" href="#socketserver.BaseServer.timeout" title="socketserver.BaseServer.timeout"><code class="xref py py-attr docutils literal"><span class="pre">timeout</span></code></a>属性。</span><span class="yiyi-st" id="yiyi-84">它还调用<a class="reference internal" href="#socketserver.BaseServer.service_actions" title="socketserver.BaseServer.service_actions"><code class="xref py py-meth docutils literal"><span class="pre">service_actions()</span></code></a>,可以由子类或mixin使用以提供特定于给定服务的操作。</span><span class="yiyi-st" id="yiyi-85">例如,<a class="reference internal" href="#socketserver.ForkingMixIn" title="socketserver.ForkingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ForkingMixIn</span></code></a>类使用<a class="reference internal" href="#socketserver.BaseServer.service_actions" title="socketserver.BaseServer.service_actions"><code class="xref py py-meth docutils literal"><span class="pre">service_actions()</span></code></a>清理僵尸子进程。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-86"><span class="versionmodified">在版本3.3中已更改:</span>添加了对<code class="docutils literal"><span class="pre">serve_forever</span></code>方法的<code class="docutils literal"><span class="pre">service_actions</span></code>调用。</span></p></div></dd></dl><dl class="method"><dt id="socketserver.BaseServer.service_actions"><span class="yiyi-st" id="yiyi-87"> <code class="descname">service_actions</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-88">这在<a class="reference internal" href="#socketserver.BaseServer.serve_forever" title="socketserver.BaseServer.serve_forever"><code class="xref py py-meth docutils literal"><span class="pre">serve_forever()</span></code></a>循环中调用。</span><span class="yiyi-st" id="yiyi-89">此方法可以被子类或mixin类覆盖,以执行特定于给定服务的操作,例如清除操作。</span></p><div class="versionadded"><p><span class="yiyi-st" id="yiyi-90"><span class="versionmodified">版本3.3中的新功能。</span></span></p></div></dd></dl><dl class="method"><dt id="socketserver.BaseServer.shutdown"><span class="yiyi-st" id="yiyi-91"> <code class="descname">shutdown</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-92">告诉<a class="reference internal" href="#socketserver.BaseServer.serve_forever" title="socketserver.BaseServer.serve_forever"><code class="xref py py-meth docutils literal"><span class="pre">serve_forever()</span></code></a>循环停止并等待,直到它。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseServer.server_close"><span class="yiyi-st" id="yiyi-93"> <code class="descname">server_close</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-94">清理服务器。</span><span class="yiyi-st" id="yiyi-95">可能被覆盖。</span></p></dd></dl><dl class="attribute"><dt id="socketserver.BaseServer.address_family"><span class="yiyi-st" id="yiyi-96"> <code class="descname">address_family</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-97">服务器的套接字所属的协议族。</span><span class="yiyi-st" id="yiyi-98">常见示例为<a class="reference internal" href="socket.html#socket.AF_INET" title="socket.AF_INET"><code class="xref py py-const docutils literal"><span class="pre">socket.AF_INET</span></code></a>和<a class="reference internal" href="socket.html#socket.AF_UNIX" title="socket.AF_UNIX"><code class="xref py py-const docutils literal"><span class="pre">socket.AF_UNIX</span></code></a>。</span></p></dd></dl><dl class="attribute"><dt id="socketserver.BaseServer.RequestHandlerClass"><span class="yiyi-st" id="yiyi-99"> <code class="descname">RequestHandlerClass</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-100">用户提供的请求处理程序类;将为每个请求创建此类的实例。</span></p></dd></dl><dl class="attribute"><dt id="socketserver.BaseServer.server_address"><span class="yiyi-st" id="yiyi-101"> <code class="descname">server_address</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-102">服务器正在侦听的地址。</span><span class="yiyi-st" id="yiyi-103">地址的格式因协议族而异;有关详细信息,请参阅<a class="reference internal" href="socket.html#module-socket" title="socket: Low-level networking interface."><code class="xref py py-mod docutils literal"><span class="pre">socket</span></code></a>模块的文档。</span><span class="yiyi-st" id="yiyi-104">对于Internet协议,这是一个包含提供地址的字符串和整数端口号的元组:<code class="docutils literal"><span class="pre">('127.0.0.1',</span> <span class="pre">80)</span> t0 >。</code></span></p></dd></dl><dl class="attribute"><dt id="socketserver.BaseServer.socket"><span class="yiyi-st" id="yiyi-105"> <code class="descname">socket</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-106">服务器将侦听传入请求的套接字对象。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-107">服务器类支持以下类变量:</span></p><dl class="attribute"><dt id="socketserver.BaseServer.allow_reuse_address"><span class="yiyi-st" id="yiyi-108"> <code class="descname">allow_reuse_address</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-109">服务器是否将允许重用地址。</span><span class="yiyi-st" id="yiyi-110">默认为<a class="reference internal" href="constants.html#False" title="False"><code class="xref py py-const docutils literal"><span class="pre">False</span></code></a>,可以在子类中设置以更改策略。</span></p></dd></dl><dl class="attribute"><dt id="socketserver.BaseServer.request_queue_size"><span class="yiyi-st" id="yiyi-111"> <code class="descname">request_queue_size</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-112">请求队列的大小。</span><span class="yiyi-st" id="yiyi-113">如果处理单个请求需要很长时间,则在服务器繁忙时到达的任何请求都会放入一个队列,最多可到<a class="reference internal" href="#socketserver.BaseServer.request_queue_size" title="socketserver.BaseServer.request_queue_size"><code class="xref py py-attr docutils literal"><span class="pre">request_queue_size</span></code></a>个请求。</span><span class="yiyi-st" id="yiyi-114">一旦队列已满,来自客户端的进一步请求将获得“连接被拒绝”错误。</span><span class="yiyi-st" id="yiyi-115">默认值通常为5,但这可以被子类覆盖。</span></p></dd></dl><dl class="attribute"><dt id="socketserver.BaseServer.socket_type"><span class="yiyi-st" id="yiyi-116"> <code class="descname">socket_type</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-117">服务器使用的套接字类型; <a class="reference internal" href="socket.html#socket.SOCK_STREAM" title="socket.SOCK_STREAM"><code class="xref py py-const docutils literal"><span class="pre">socket.SOCK_STREAM</span></code></a>和<a class="reference internal" href="socket.html#socket.SOCK_DGRAM" title="socket.SOCK_DGRAM"><code class="xref py py-const docutils literal"><span class="pre">socket.SOCK_DGRAM</span></code></a>是两个常见值。</span></p></dd></dl><dl class="attribute"><dt id="socketserver.BaseServer.timeout"><span class="yiyi-st" id="yiyi-118"> <code class="descname">timeout</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-119">超时持续时间(以秒为单位),或<a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a>(如果不需要超时)。</span><span class="yiyi-st" id="yiyi-120">如果<a class="reference internal" href="#socketserver.BaseServer.handle_request" title="socketserver.BaseServer.handle_request"><code class="xref py py-meth docutils literal"><span class="pre">handle_request()</span></code></a>在超时期限内未收到传入请求,则会调用<a class="reference internal" href="#socketserver.BaseServer.handle_timeout" title="socketserver.BaseServer.handle_timeout"><code class="xref py py-meth docutils literal"><span class="pre">handle_timeout()</span></code></a>方法。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-121">有各种服务器方法可以被基本服务器类的子类覆盖,例如<a class="reference internal" href="#socketserver.TCPServer" title="socketserver.TCPServer"><code class="xref py py-class docutils literal"><span class="pre">TCPServer</span></code></a>;这些方法对服务器对象的外部用户无用。</span></p><dl class="method"><dt id="socketserver.BaseServer.finish_request"><span class="yiyi-st" id="yiyi-122"> <code class="descname">finish_request</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-123">实际上通过实例化<a class="reference internal" href="#socketserver.BaseServer.RequestHandlerClass" title="socketserver.BaseServer.RequestHandlerClass"><code class="xref py py-attr docutils literal"><span class="pre">RequestHandlerClass</span></code></a>并调用其<a class="reference internal" href="#socketserver.BaseRequestHandler.handle" title="socketserver.BaseRequestHandler.handle"><code class="xref py py-meth docutils literal"><span class="pre">handle()</span></code></a>方法来处理请求。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseServer.get_request"><span class="yiyi-st" id="yiyi-124"> <code class="descname">get_request</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-125">必须接受来自套接字的请求,并返回包含要用于与客户端通信的<em>新</em>套接字对象和客户端地址的2元组。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseServer.handle_error"><span class="yiyi-st" id="yiyi-126"> <code class="descname">handle_error</code><span class="sig-paren">(</span><em>request</em>, <em>client_address</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-127">如果<a class="reference internal" href="#socketserver.BaseServer.RequestHandlerClass" title="socketserver.BaseServer.RequestHandlerClass"><code class="xref py py-attr docutils literal"><span class="pre">RequestHandlerClass</span></code></a>实例引发异常的<a class="reference internal" href="#socketserver.BaseRequestHandler.handle" title="socketserver.BaseRequestHandler.handle"><code class="xref py py-meth docutils literal"><span class="pre">handle()</span></code></a>方法,则调用此函数。</span><span class="yiyi-st" id="yiyi-128">默认操作是将回溯打印到标准输出,并继续处理进一步的请求。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseServer.handle_timeout"><span class="yiyi-st" id="yiyi-129"> <code class="descname">handle_timeout</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-130">当<a class="reference internal" href="#socketserver.BaseServer.timeout" title="socketserver.BaseServer.timeout"><code class="xref py py-attr docutils literal"><span class="pre">timeout</span></code></a>属性设置为除<a class="reference internal" href="constants.html#None" title="None"><code class="xref py py-const docutils literal"><span class="pre">None</span></code></a>之外的值并且超时时间已过且未接收到任何请求时,将调用此函数。</span><span class="yiyi-st" id="yiyi-131">分叉服务器的默认操作是收集已退出的任何子进程的状态,而在线程服务器中此方法不执行任何操作。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseServer.process_request"><span class="yiyi-st" id="yiyi-132"> <code class="descname">process_request</code><span class="sig-paren">(</span><em>request</em>, <em>client_address</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-133">Calls <a class="reference internal" href="#socketserver.BaseServer.finish_request" title="socketserver.BaseServer.finish_request"><code class="xref py py-meth docutils literal"><span class="pre">finish_request()</span></code></a> to create an instance of the <a class="reference internal" href="#socketserver.BaseServer.RequestHandlerClass" title="socketserver.BaseServer.RequestHandlerClass"><code class="xref py py-attr docutils literal"><span class="pre">RequestHandlerClass</span></code></a>. </span><span class="yiyi-st" id="yiyi-134">如果需要,此函数可以创建一个新的进程或线程来处理请求; <a class="reference internal" href="#socketserver.ForkingMixIn" title="socketserver.ForkingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ForkingMixIn</span></code></a>和<a class="reference internal" href="#socketserver.ThreadingMixIn" title="socketserver.ThreadingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ThreadingMixIn</span></code></a>类执行此操作。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseServer.server_activate"><span class="yiyi-st" id="yiyi-135"> <code class="descname">server_activate</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-136">由服务器的构造函数调用以激活服务器。</span><span class="yiyi-st" id="yiyi-137">TCP服务器的默认行为只是调用服务器套接字上的<a class="reference internal" href="socket.html#socket.socket.listen" title="socket.socket.listen"><code class="xref py py-meth docutils literal"><span class="pre">listen()</span></code></a>。</span><span class="yiyi-st" id="yiyi-138">可能被覆盖。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseServer.server_bind"><span class="yiyi-st" id="yiyi-139"> <code class="descname">server_bind</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-140">由服务器的构造函数调用以将套接字绑定到所需的地址。</span><span class="yiyi-st" id="yiyi-141">可能被覆盖。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseServer.verify_request"><span class="yiyi-st" id="yiyi-142"> <code class="descname">verify_request</code><span class="sig-paren">(</span><em>request</em>, <em>client_address</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-143">必须返回布尔值;如果值为<a class="reference internal" href="constants.html#True" title="True"><code class="xref py py-const docutils literal"><span class="pre">True</span></code></a>,则会处理请求,如果它<a class="reference internal" href="constants.html#False" title="False"><code class="xref py py-const docutils literal"><span class="pre">False</span></code></a>,则请求将被拒绝。</span><span class="yiyi-st" id="yiyi-144">可以覆盖此功能以实现服务器的访问控制。</span><span class="yiyi-st" id="yiyi-145">默认实现总是返回<a class="reference internal" href="constants.html#True" title="True"><code class="xref py py-const docutils literal"><span class="pre">True</span></code></a>。</span></p></dd></dl></dd></dl></div><div class="section" id="request-handler-objects"><h2><span class="yiyi-st" id="yiyi-146">21.21.3. </span><span class="yiyi-st" id="yiyi-147">请求处理程序对象</span></h2><dl class="class"><dt id="socketserver.BaseRequestHandler"><span class="yiyi-st" id="yiyi-148"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">BaseRequestHandler</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-149">这是所有请求处理程序对象的超类。</span><span class="yiyi-st" id="yiyi-150">它定义了接口,如下所示。</span><span class="yiyi-st" id="yiyi-151">具体的请求处理程序子类必须定义新的<a class="reference internal" href="#socketserver.BaseRequestHandler.handle" title="socketserver.BaseRequestHandler.handle"><code class="xref py py-meth docutils literal"><span class="pre">handle()</span></code></a>方法,并且可以覆盖任何其他方法。</span><span class="yiyi-st" id="yiyi-152">为每个请求创建子类的新实例。</span></p><dl class="method"><dt id="socketserver.BaseRequestHandler.setup"><span class="yiyi-st" id="yiyi-153"> <code class="descname">setup</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-154">在<a class="reference internal" href="#socketserver.BaseRequestHandler.handle" title="socketserver.BaseRequestHandler.handle"><code class="xref py py-meth docutils literal"><span class="pre">handle()</span></code></a>方法之前调用以执行所需的任何初始化操作。</span><span class="yiyi-st" id="yiyi-155">默认实现什么也不做。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseRequestHandler.handle"><span class="yiyi-st" id="yiyi-156"> <code class="descname">handle</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-157">此函数必须执行服务请求所需的所有工作。</span><span class="yiyi-st" id="yiyi-158">默认实现什么也不做。</span><span class="yiyi-st" id="yiyi-159">几个实例属性可用于它;该请求可用作<code class="xref py py-attr docutils literal"><span class="pre">self.request</span></code>;客户端地址为<code class="xref py py-attr docutils literal"><span class="pre">self.client_address</span></code>;和服务器实例为<code class="xref py py-attr docutils literal"><span class="pre">self.server</span></code>,以防需要访问每个服务器的信息。</span></p><p><span class="yiyi-st" id="yiyi-160"><code class="xref py py-attr docutils literal"><span class="pre">self.request</span></code>的类型对于数据报或流服务不同。</span><span class="yiyi-st" id="yiyi-161">对于流服务,<code class="xref py py-attr docutils literal"><span class="pre">self.request</span></code>是一个套接字对象;对于数据报服务,<code class="xref py py-attr docutils literal"><span class="pre">self.request</span></code>是一对字符串和套接字。</span></p></dd></dl><dl class="method"><dt id="socketserver.BaseRequestHandler.finish"><span class="yiyi-st" id="yiyi-162"> <code class="descname">finish</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-163">在<a class="reference internal" href="#socketserver.BaseRequestHandler.handle" title="socketserver.BaseRequestHandler.handle"><code class="xref py py-meth docutils literal"><span class="pre">handle()</span></code></a>方法后调用以执行所需的任何清理操作。</span><span class="yiyi-st" id="yiyi-164">默认实现什么也不做。</span><span class="yiyi-st" id="yiyi-165">如果<a class="reference internal" href="#socketserver.BaseRequestHandler.setup" title="socketserver.BaseRequestHandler.setup"><code class="xref py py-meth docutils literal"><span class="pre">setup()</span></code></a>引发异常,则不会调用此函数。</span></p></dd></dl></dd></dl><dl class="class"><dt id="socketserver.StreamRequestHandler"><span class="yiyi-st" id="yiyi-166"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">StreamRequestHandler</code></span></dt><dt id="socketserver.DatagramRequestHandler"><span class="yiyi-st" id="yiyi-167"> <em class="property">class </em><code class="descclassname">socketserver.</code><code class="descname">DatagramRequestHandler</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-168">这些<a class="reference internal" href="#socketserver.BaseRequestHandler" title="socketserver.BaseRequestHandler"><code class="xref py py-class docutils literal"><span class="pre">BaseRequestHandler</span></code></a>子类会覆盖<a class="reference internal" href="#socketserver.BaseRequestHandler.setup" title="socketserver.BaseRequestHandler.setup"><code class="xref py py-meth docutils literal"><span class="pre">setup()</span></code></a>和<a class="reference internal" href="#socketserver.BaseRequestHandler.finish" title="socketserver.BaseRequestHandler.finish"><code class="xref py py-meth docutils literal"><span class="pre">finish()</span></code></a>方法,并提供<code class="xref py py-attr docutils literal"><span class="pre">self.rfile</span></code>和<code class="xref py py-attr docutils literal"><span class="pre">self.wfile</span></code>属性。</span><span class="yiyi-st" id="yiyi-169">可以分别读取或写入<code class="xref py py-attr docutils literal"><span class="pre">self.rfile</span></code>和<code class="xref py py-attr docutils literal"><span class="pre">self.wfile</span></code>属性,以获取请求数据或将数据返回给客户端。</span></p></dd></dl></div><div class="section" id="examples"><h2><span class="yiyi-st" id="yiyi-170">21.21.4. </span><span class="yiyi-st" id="yiyi-171">Examples</span></h2><div class="section" id="socketserver-tcpserver-example"><h3><span class="yiyi-st" id="yiyi-172">21.21.4.1. <a class="reference internal" href="#socketserver.TCPServer" title="socketserver.TCPServer"><code class="xref py py-class docutils literal"><span class="pre">socketserver.TCPServer</span></code></a>示例</span></h3><p><span class="yiyi-st" id="yiyi-173">这是服务器端:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">socketserver</span>
|
||
|
||
<span class="k">class</span> <span class="nc">MyTCPHandler</span><span class="p">(</span><span class="n">socketserver</span><span class="o">.</span><span class="n">BaseRequestHandler</span><span class="p">):</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd"> The request handler class for our server.</span>
|
||
|
||
<span class="sd"> It is instantiated once per connection to the server, and must</span>
|
||
<span class="sd"> override the handle() method to implement communication to the</span>
|
||
<span class="sd"> client.</span>
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="k">def</span> <span class="nf">handle</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># self.request is the TCP socket connected to the client</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2"> wrote:"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">client_address</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">)</span>
|
||
<span class="c1"># just send back the same data, but upper-cased</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">sendall</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">upper</span><span class="p">())</span>
|
||
|
||
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
||
<span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span> <span class="o">=</span> <span class="s2">"localhost"</span><span class="p">,</span> <span class="mi">9999</span>
|
||
|
||
<span class="c1"># Create the server, binding to localhost on port 9999</span>
|
||
<span class="n">server</span> <span class="o">=</span> <span class="n">socketserver</span><span class="o">.</span><span class="n">TCPServer</span><span class="p">((</span><span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span><span class="p">),</span> <span class="n">MyTCPHandler</span><span class="p">)</span>
|
||
|
||
<span class="c1"># Activate the server; this will keep running until you</span>
|
||
<span class="c1"># interrupt the program with Ctrl-C</span>
|
||
<span class="n">server</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-174">使用流(类似文件的对象,通过提供标准文件接口简化通信)的另一个请求处理程序类:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">MyTCPHandler</span><span class="p">(</span><span class="n">socketserver</span><span class="o">.</span><span class="n">StreamRequestHandler</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">handle</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># self.rfile is a file-like object created by the handler;</span>
|
||
<span class="c1"># we can now use e.g. readline() instead of raw recv() calls</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rfile</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2"> wrote:"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">client_address</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">)</span>
|
||
<span class="c1"># Likewise, self.wfile is a file-like object used to write back</span>
|
||
<span class="c1"># to the client</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">wfile</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">upper</span><span class="p">())</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-175">区别在于第二个处理程序中的<code class="docutils literal"><span class="pre">readline()</span></code>多次调用<code class="docutils literal"><span class="pre">recv()</span></code>,直到遇到换行符,而单个<code class="docutils literal"><span class="pre">recv()</span></code>在第一个处理程序中的调用只会返回在一个<code class="docutils literal"><span class="pre">sendall()</span></code>调用中从客户端发送的内容。</span></p><p><span class="yiyi-st" id="yiyi-176">这是客户端:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">socket</span>
|
||
<span class="kn">import</span> <span class="nn">sys</span>
|
||
|
||
<span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span> <span class="o">=</span> <span class="s2">"localhost"</span><span class="p">,</span> <span class="mi">9999</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="s2">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span>
|
||
|
||
<span class="c1"># Create a socket (SOCK_STREAM means a TCP socket)</span>
|
||
<span class="k">with</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span> <span class="k">as</span> <span class="n">sock</span><span class="p">:</span>
|
||
<span class="c1"># Connect to server and send data</span>
|
||
<span class="n">sock</span><span class="o">.</span><span class="n">connect</span><span class="p">((</span><span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span><span class="p">))</span>
|
||
<span class="n">sock</span><span class="o">.</span><span class="n">sendall</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="n">data</span> <span class="o">+</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="s2">"utf-8"</span><span class="p">))</span>
|
||
|
||
<span class="c1"># Receive data from the server and shut down</span>
|
||
<span class="n">received</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">sock</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">),</span> <span class="s2">"utf-8"</span><span class="p">)</span>
|
||
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Sent: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">data</span><span class="p">))</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Received: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">received</span><span class="p">))</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-177">示例的输出应如下所示:</span></p><p><span class="yiyi-st" id="yiyi-178">服务器:</span></p><div class="highlight-shell-session"><div class="highlight"><pre><span></span><span class="gp">$</span> python TCPServer.py
|
||
<span class="go">127.0.0.1 wrote:</span>
|
||
<span class="go">b'hello world with TCP'</span>
|
||
<span class="go">127.0.0.1 wrote:</span>
|
||
<span class="go">b'python is nice'</span>
|
||
</pre></div></div><p><span class="yiyi-st" id="yiyi-179">客户:</span></p><div class="highlight-shell-session"><div class="highlight"><pre><span></span><span class="gp">$</span> python TCPClient.py hello world with TCP
|
||
<span class="go">Sent: hello world with TCP</span>
|
||
<span class="go">Received: HELLO WORLD WITH TCP</span>
|
||
<span class="gp">$</span> python TCPClient.py python is nice
|
||
<span class="go">Sent: python is nice</span>
|
||
<span class="go">Received: PYTHON IS NICE</span>
|
||
</pre></div></div></div><div class="section" id="socketserver-udpserver-example"><h3><span class="yiyi-st" id="yiyi-180">21.21.4.2. <a class="reference internal" href="#socketserver.UDPServer" title="socketserver.UDPServer"><code class="xref py py-class docutils literal"><span class="pre">socketserver.UDPServer</span></code></a>示例</span></h3><p><span class="yiyi-st" id="yiyi-181">这是服务器端:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">socketserver</span>
|
||
|
||
<span class="k">class</span> <span class="nc">MyUDPHandler</span><span class="p">(</span><span class="n">socketserver</span><span class="o">.</span><span class="n">BaseRequestHandler</span><span class="p">):</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd"> This class works similar to the TCP handler class, except that</span>
|
||
<span class="sd"> self.request consists of a pair of data and client socket, and since</span>
|
||
<span class="sd"> there is no connection the client address must be given explicitly</span>
|
||
<span class="sd"> when sending data back via sendto().</span>
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="k">def</span> <span class="nf">handle</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||
<span class="n">socket</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2"> wrote:"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">client_address</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
|
||
<span class="n">socket</span><span class="o">.</span><span class="n">sendto</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">upper</span><span class="p">(),</span> <span class="bp">self</span><span class="o">.</span><span class="n">client_address</span><span class="p">)</span>
|
||
|
||
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
||
<span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span> <span class="o">=</span> <span class="s2">"localhost"</span><span class="p">,</span> <span class="mi">9999</span>
|
||
<span class="n">server</span> <span class="o">=</span> <span class="n">socketserver</span><span class="o">.</span><span class="n">UDPServer</span><span class="p">((</span><span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span><span class="p">),</span> <span class="n">MyUDPHandler</span><span class="p">)</span>
|
||
<span class="n">server</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-182">这是客户端:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">socket</span>
|
||
<span class="kn">import</span> <span class="nn">sys</span>
|
||
|
||
<span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span> <span class="o">=</span> <span class="s2">"localhost"</span><span class="p">,</span> <span class="mi">9999</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="s2">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span>
|
||
|
||
<span class="c1"># SOCK_DGRAM is the socket type to use for UDP sockets</span>
|
||
<span class="n">sock</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_DGRAM</span><span class="p">)</span>
|
||
|
||
<span class="c1"># As you can see, there is no connect() call; UDP has no connections.</span>
|
||
<span class="c1"># Instead, data is directly sent to the recipient via sendto().</span>
|
||
<span class="n">sock</span><span class="o">.</span><span class="n">sendto</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="n">data</span> <span class="o">+</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="s2">"utf-8"</span><span class="p">),</span> <span class="p">(</span><span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span><span class="p">))</span>
|
||
<span class="n">received</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">sock</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">),</span> <span class="s2">"utf-8"</span><span class="p">)</span>
|
||
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Sent: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">data</span><span class="p">))</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Received: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">received</span><span class="p">))</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-183">示例的输出应该看起来像TCP服务器示例。</span></p></div><div class="section" id="asynchronous-mixins"><h3><span class="yiyi-st" id="yiyi-184">21.21.4.3. </span><span class="yiyi-st" id="yiyi-185">Asynchronous Mixins</span></h3><p><span class="yiyi-st" id="yiyi-186">要构建异步处理程序,请使用<a class="reference internal" href="#socketserver.ThreadingMixIn" title="socketserver.ThreadingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ThreadingMixIn</span></code></a>和<a class="reference internal" href="#socketserver.ForkingMixIn" title="socketserver.ForkingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ForkingMixIn</span></code></a>类。</span></p><p><span class="yiyi-st" id="yiyi-187"><a class="reference internal" href="#socketserver.ThreadingMixIn" title="socketserver.ThreadingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ThreadingMixIn</span></code></a>类的示例:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">socket</span>
|
||
<span class="kn">import</span> <span class="nn">threading</span>
|
||
<span class="kn">import</span> <span class="nn">socketserver</span>
|
||
|
||
<span class="k">class</span> <span class="nc">ThreadedTCPRequestHandler</span><span class="p">(</span><span class="n">socketserver</span><span class="o">.</span><span class="n">BaseRequestHandler</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">handle</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">),</span> <span class="s1">'ascii'</span><span class="p">)</span>
|
||
<span class="n">cur_thread</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">current_thread</span><span class="p">()</span>
|
||
<span class="n">response</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2">: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">cur_thread</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">data</span><span class="p">),</span> <span class="s1">'ascii'</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">sendall</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>
|
||
|
||
<span class="k">class</span> <span class="nc">ThreadedTCPServer</span><span class="p">(</span><span class="n">socketserver</span><span class="o">.</span><span class="n">ThreadingMixIn</span><span class="p">,</span> <span class="n">socketserver</span><span class="o">.</span><span class="n">TCPServer</span><span class="p">):</span>
|
||
<span class="k">pass</span>
|
||
|
||
<span class="k">def</span> <span class="nf">client</span><span class="p">(</span><span class="n">ip</span><span class="p">,</span> <span class="n">port</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
|
||
<span class="k">with</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span> <span class="k">as</span> <span class="n">sock</span><span class="p">:</span>
|
||
<span class="n">sock</span><span class="o">.</span><span class="n">connect</span><span class="p">((</span><span class="n">ip</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span>
|
||
<span class="n">sock</span><span class="o">.</span><span class="n">sendall</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="s1">'ascii'</span><span class="p">))</span>
|
||
<span class="n">response</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">sock</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">),</span> <span class="s1">'ascii'</span><span class="p">)</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Received: </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">response</span><span class="p">))</span>
|
||
|
||
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
||
<span class="c1"># Port 0 means to select an arbitrary unused port</span>
|
||
<span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span> <span class="o">=</span> <span class="s2">"localhost"</span><span class="p">,</span> <span class="mi">0</span>
|
||
|
||
<span class="n">server</span> <span class="o">=</span> <span class="n">ThreadedTCPServer</span><span class="p">((</span><span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span><span class="p">),</span> <span class="n">ThreadedTCPRequestHandler</span><span class="p">)</span>
|
||
<span class="n">ip</span><span class="p">,</span> <span class="n">port</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">server_address</span>
|
||
|
||
<span class="c1"># Start a thread with the server -- that thread will then start one</span>
|
||
<span class="c1"># more thread for each request</span>
|
||
<span class="n">server_thread</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">server</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">)</span>
|
||
<span class="c1"># Exit the server thread when the main thread terminates</span>
|
||
<span class="n">server_thread</span><span class="o">.</span><span class="n">daemon</span> <span class="o">=</span> <span class="kc">True</span>
|
||
<span class="n">server_thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Server loop running in thread:"</span><span class="p">,</span> <span class="n">server_thread</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
|
||
|
||
<span class="n">client</span><span class="p">(</span><span class="n">ip</span><span class="p">,</span> <span class="n">port</span><span class="p">,</span> <span class="s2">"Hello World 1"</span><span class="p">)</span>
|
||
<span class="n">client</span><span class="p">(</span><span class="n">ip</span><span class="p">,</span> <span class="n">port</span><span class="p">,</span> <span class="s2">"Hello World 2"</span><span class="p">)</span>
|
||
<span class="n">client</span><span class="p">(</span><span class="n">ip</span><span class="p">,</span> <span class="n">port</span><span class="p">,</span> <span class="s2">"Hello World 3"</span><span class="p">)</span>
|
||
|
||
<span class="n">server</span><span class="o">.</span><span class="n">shutdown</span><span class="p">()</span>
|
||
<span class="n">server</span><span class="o">.</span><span class="n">server_close</span><span class="p">()</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-188">示例的输出应如下所示:</span></p><div class="highlight-shell-session"><div class="highlight"><pre><span></span><span class="gp">$</span> python ThreadedTCPServer.py
|
||
<span class="go">Server loop running in thread: Thread-1</span>
|
||
<span class="go">Received: Thread-2: Hello World 1</span>
|
||
<span class="go">Received: Thread-3: Hello World 2</span>
|
||
<span class="go">Received: Thread-4: Hello World 3</span>
|
||
</pre></div></div><p><span class="yiyi-st" id="yiyi-189"><a class="reference internal" href="#socketserver.ForkingMixIn" title="socketserver.ForkingMixIn"><code class="xref py py-class docutils literal"><span class="pre">ForkingMixIn</span></code></a>类以相同的方式使用,除了服务器将为每个请求生成一个新进程。</span></p></div></div></div></div> |