uTools-Manuals/docs/python/asynchat.html
2019-04-21 11:50:48 +08:00

39 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="body" role="main"><div class="section" id="module-asynchat"><h1><span class="yiyi-st" id="yiyi-10">18.7。 <a class="reference internal" href="#module-asynchat" title="asynchat: Support for asynchronous command/response protocols."><code class="xref py py-mod docutils literal"><span class="pre">asynchat</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/asynchat.py">Lib/asynchat.py</a></span></p><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-12">注意</span></p><p class="last"><span class="yiyi-st" id="yiyi-13">此模块仅用于向后兼容。</span><span class="yiyi-st" id="yiyi-14">对于新代码,我们建议使用<a class="reference internal" href="asyncio.html#module-asyncio" title="asyncio: Asynchronous I/O, event loop, coroutines and tasks."><code class="xref py py-mod docutils literal"><span class="pre">asyncio</span></code></a></span></p></div><p><span class="yiyi-st" id="yiyi-15">该模块建立在<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><span class="yiyi-st" id="yiyi-16"><a class="reference internal" href="#module-asynchat" title="asynchat: Support for asynchronous command/response protocols."><code class="xref py py-mod docutils literal"><span class="pre">asynchat</span></code></a>定义您的子类的抽象类<a class="reference internal" href="#asynchat.async_chat" title="asynchat.async_chat"><code class="xref py py-class docutils literal"><span class="pre">async_chat</span></code></a>,提供<code class="xref py py-meth docutils literal"><span class="pre">collect_incoming_data()</span></code><code class="xref py py-meth docutils literal"><span class="pre">found_terminator()</span></code></span><span class="yiyi-st" id="yiyi-17">它使用与<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>相同的异步循环,并且两种类型的通道<a class="reference internal" href="asyncore.html#asyncore.dispatcher" title="asyncore.dispatcher"><code class="xref py py-class docutils literal"><span class="pre">asyncore.dispatcher</span></code></a><a class="reference internal" href="#asynchat.async_chat" title="asynchat.async_chat"><code class="xref py py-class docutils literal"><span class="pre">asynchat.async_chat</span></code></a>可以自由混合通道映射。</span><span class="yiyi-st" id="yiyi-18">通常,在接收传入连接请求时,<a class="reference internal" href="asyncore.html#asyncore.dispatcher" title="asyncore.dispatcher"><code class="xref py py-class docutils literal"><span class="pre">asyncore.dispatcher</span></code></a>服务器通道会生成新的<a class="reference internal" href="#asynchat.async_chat" title="asynchat.async_chat"><code class="xref py py-class docutils literal"><span class="pre">asynchat.async_chat</span></code></a>通道对象。</span></p><dl class="class"><dt id="asynchat.async_chat"><span class="yiyi-st" id="yiyi-19"> <em class="property">class </em><code class="descclassname">asynchat.</code><code class="descname">async_chat</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-20">此类是<a class="reference internal" href="asyncore.html#asyncore.dispatcher" title="asyncore.dispatcher"><code class="xref py py-class docutils literal"><span class="pre">asyncore.dispatcher</span></code></a>的抽象子类。</span><span class="yiyi-st" id="yiyi-21">要实际使用代码,必须将<a class="reference internal" href="#asynchat.async_chat" title="asynchat.async_chat"><code class="xref py py-class docutils literal"><span class="pre">async_chat</span></code></a>作为子类,提供有意义的<a class="reference internal" href="#asynchat.async_chat.collect_incoming_data" title="asynchat.async_chat.collect_incoming_data"><code class="xref py py-meth docutils literal"><span class="pre">collect_incoming_data()</span></code></a><a class="reference internal" href="#asynchat.async_chat.found_terminator" title="asynchat.async_chat.found_terminator"><code class="xref py py-meth docutils literal"><span class="pre">found_terminator()</span></code></a>方法。</span><span class="yiyi-st" id="yiyi-22">可以使用<a class="reference internal" href="asyncore.html#asyncore.dispatcher" title="asyncore.dispatcher"><code class="xref py py-class docutils literal"><span class="pre">asyncore.dispatcher</span></code></a>方法,虽然在消息/响应上下文中并不都有意义。</span></p><p><span class="yiyi-st" id="yiyi-23"><a class="reference internal" href="asyncore.html#asyncore.dispatcher" title="asyncore.dispatcher"><code class="xref py py-class docutils literal"><span class="pre">asyncore.dispatcher</span></code></a><a class="reference internal" href="#asynchat.async_chat" title="asynchat.async_chat"><code class="xref py py-class docutils literal"><span class="pre">async_chat</span></code></a>定义了在<code class="xref c c-func docutils literal"><span class="pre">select()</span></code>调用后通过分析套接字条件生成的一组事件。</span><span class="yiyi-st" id="yiyi-24">一旦轮询循环已启动,事件处理框架调用<a class="reference internal" href="#asynchat.async_chat" title="asynchat.async_chat"><code class="xref py py-class docutils literal"><span class="pre">async_chat</span></code></a>对象的方法,而对程序员没有动作。</span></p><p><span class="yiyi-st" id="yiyi-25">可以修改两个类属性,以提高性能,或者甚至可以节省内存。</span></p><dl class="data"><dt id="asynchat.async_chat.ac_in_buffer_size"><span class="yiyi-st" id="yiyi-26"> <code class="descname">ac_in_buffer_size</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-27">异步输入缓冲区大小(默认值<code class="docutils literal"><span class="pre">4096</span></code>)。</span></p></dd></dl><dl class="data"><dt id="asynchat.async_chat.ac_out_buffer_size"><span class="yiyi-st" id="yiyi-28"> <code class="descname">ac_out_buffer_size</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-29">异步输出缓冲区大小(默认值<code class="docutils literal"><span class="pre">4096</span></code>)。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-30"><a class="reference internal" href="asyncore.html#asyncore.dispatcher" title="asyncore.dispatcher"><code class="xref py py-class docutils literal"><span class="pre">asyncore.dispatcher</span></code></a>不同,<a class="reference internal" href="#asynchat.async_chat" title="asynchat.async_chat"><code class="xref py py-class docutils literal"><span class="pre">async_chat</span></code></a>允许您定义<em>生产者</em>的先入先出队列fifo</span><span class="yiyi-st" id="yiyi-31">生产者需要只有一个方法,<code class="xref py py-meth docutils literal"><span class="pre">more()</span></code>,它应该返回要在通道上传输的数据。</span><span class="yiyi-st" id="yiyi-32">生产者指示疲劳(<em>,即</em></span><span class="yiyi-st" id="yiyi-33">通过使其<code class="xref py py-meth docutils literal"><span class="pre">more()</span></code>方法返回空字节对象,它不包含更多数据)。</span><span class="yiyi-st" id="yiyi-34">此时,<a class="reference internal" href="#asynchat.async_chat" title="asynchat.async_chat"><code class="xref py py-class docutils literal"><span class="pre">async_chat</span></code></a>对象从fifo中删除生产者并开始使用下一个生产者如果有的话</span><span class="yiyi-st" id="yiyi-35">当生产者fifo为空时<code class="xref py py-meth docutils literal"><span class="pre">handle_write()</span></code>方法不执行任何操作。</span><span class="yiyi-st" id="yiyi-36">您使用通道对象的<a class="reference internal" href="#asynchat.async_chat.set_terminator" title="asynchat.async_chat.set_terminator"><code class="xref py py-meth docutils literal"><span class="pre">set_terminator()</span></code></a>方法来描述如何识别来自远程端点的传入传输的结束或重要断点。</span></p><p><span class="yiyi-st" id="yiyi-37">要构建一个有效的<a class="reference internal" href="#asynchat.async_chat" title="asynchat.async_chat"><code class="xref py py-class docutils literal"><span class="pre">async_chat</span></code></a>子类,输入方法<a class="reference internal" href="#asynchat.async_chat.collect_incoming_data" title="asynchat.async_chat.collect_incoming_data"><code class="xref py py-meth docutils literal"><span class="pre">collect_incoming_data()</span></code></a><a class="reference internal" href="#asynchat.async_chat.found_terminator" title="asynchat.async_chat.found_terminator"><code class="xref py py-meth docutils literal"><span class="pre">found_terminator()</span></code></a>必须处理通道异步接收的数据。</span><span class="yiyi-st" id="yiyi-38">方法如下所述。</span></p></dd></dl><dl class="method"><dt id="asynchat.async_chat.close_when_done"><span class="yiyi-st" id="yiyi-39"> <code class="descclassname">async_chat.</code><code class="descname">close_when_done</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-40"><code class="docutils literal"><span class="pre">None</span></code>推送到制片人fifo。</span><span class="yiyi-st" id="yiyi-41">当这个制片人从fifo弹出时它导致通道被关闭。</span></p></dd></dl><dl class="method"><dt id="asynchat.async_chat.collect_incoming_data"><span class="yiyi-st" id="yiyi-42"> <code class="descclassname">async_chat.</code><code class="descname">collect_incoming_data</code><span class="sig-paren">(</span><em>data</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-43"><em>数据</em>调用,保存任意数量的接收数据。</span><span class="yiyi-st" id="yiyi-44">必须重写的默认方法引发一个<a class="reference internal" href="exceptions.html#NotImplementedError" title="NotImplementedError"><code class="xref py py-exc docutils literal"><span class="pre">NotImplementedError</span></code></a>异常。</span></p></dd></dl><dl class="method"><dt id="asynchat.async_chat.discard_buffers"><span class="yiyi-st" id="yiyi-45"> <code class="descclassname">async_chat.</code><code class="descname">discard_buffers</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-46">在紧急情况下,该方法将丢弃保存在输入和/或输出缓冲器和生产者fifo中的任何数据。</span></p></dd></dl><dl class="method"><dt id="asynchat.async_chat.found_terminator"><span class="yiyi-st" id="yiyi-47"> <code class="descclassname">async_chat.</code><code class="descname">found_terminator</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-48">当传入数据流与<a class="reference internal" href="#asynchat.async_chat.set_terminator" title="asynchat.async_chat.set_terminator"><code class="xref py py-meth docutils literal"><span class="pre">set_terminator()</span></code></a>设置的终止条件匹配时调用。</span><span class="yiyi-st" id="yiyi-49">必须重写的默认方法引发一个<a class="reference internal" href="exceptions.html#NotImplementedError" title="NotImplementedError"><code class="xref py py-exc docutils literal"><span class="pre">NotImplementedError</span></code></a>异常。</span><span class="yiyi-st" id="yiyi-50">缓冲的输入数据应该通过实例属性可用。</span></p></dd></dl><dl class="method"><dt id="asynchat.async_chat.get_terminator"><span class="yiyi-st" id="yiyi-51"> <code class="descclassname">async_chat.</code><code class="descname">get_terminator</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-52">返回通道的当前终结符。</span></p></dd></dl><dl class="method"><dt id="asynchat.async_chat.push"><span class="yiyi-st" id="yiyi-53"> <code class="descclassname">async_chat.</code><code class="descname">push</code><span class="sig-paren">(</span><em>data</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-54">将数据推送到通道的fifo以确保其传输。</span><span class="yiyi-st" id="yiyi-55">这是所有你需要做的是让通道将数据写入网络,虽然可以在更复杂的方案中使用自己的生产者来实现加密和分块。</span></p></dd></dl><dl class="method"><dt id="asynchat.async_chat.push_with_producer"><span class="yiyi-st" id="yiyi-56"> <code class="descclassname">async_chat.</code><code class="descname">push_with_producer</code><span class="sig-paren">(</span><em>producer</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-57">获取生产者对象并将其添加到与通道相关联的生成者fifo。</span><span class="yiyi-st" id="yiyi-58">当所有当前推送的生产者已经耗尽时,通道将通过调用其<code class="xref py py-meth docutils literal"><span class="pre">more()</span></code>方法来消耗该生产者的数据,并将数据发送到远程端点。</span></p></dd></dl><dl class="method"><dt id="asynchat.async_chat.set_terminator"><span class="yiyi-st" id="yiyi-59"> <code class="descclassname">async_chat.</code><code class="descname">set_terminator</code><span class="sig-paren">(</span><em>term</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-60">设置要在通道上识别的终止条件。</span><span class="yiyi-st" id="yiyi-61"><code class="docutils literal"><span class="pre">term</span></code>可以是三种类型的值中的任何一种,对应于处理传入协议数据的三种不同方式。</span></p><table border="1" class="docutils"><thead valign="bottom"><tr class="row-odd"><th class="head"><span class="yiyi-st" id="yiyi-62">术语</span></th><th class="head"><span class="yiyi-st" id="yiyi-63">描述</span></th></tr></thead><tbody valign="top"><tr class="row-even"><td><span class="yiyi-st" id="yiyi-64"><em>字符串 T0&gt;</em></span></td><td><span class="yiyi-st" id="yiyi-65">当在输入流中找到字符串时,将调用<a class="reference internal" href="#asynchat.async_chat.found_terminator" title="asynchat.async_chat.found_terminator"><code class="xref py py-meth docutils literal"><span class="pre">found_terminator()</span></code></a></span></td></tr><tr class="row-odd"><td><span class="yiyi-st" id="yiyi-66"><em>整数 T0&gt;</em></span></td><td><span class="yiyi-st" id="yiyi-67">当接收到指定数量的字符时,将调用<a class="reference internal" href="#asynchat.async_chat.found_terminator" title="asynchat.async_chat.found_terminator"><code class="xref py py-meth docutils literal"><span class="pre">found_terminator()</span></code></a></span></td></tr><tr class="row-even"><td><span class="yiyi-st" id="yiyi-68"><code class="docutils literal"><span class="pre">None</span></code></span></td><td><span class="yiyi-st" id="yiyi-69">该频道继续永远收集数据</span></td></tr></tbody></table><p><span class="yiyi-st" id="yiyi-70">注意,在调用<a class="reference internal" href="#asynchat.async_chat.found_terminator" title="asynchat.async_chat.found_terminator"><code class="xref py py-meth docutils literal"><span class="pre">found_terminator()</span></code></a>之后,通道后面的任何数据都可用于读取。</span></p></dd></dl><div class="section" id="asynchat-example"><h2><span class="yiyi-st" id="yiyi-71">18.7.1. asynchat示例</span></h2><p><span class="yiyi-st" id="yiyi-72">以下部分示例显示如何使用<a class="reference internal" href="#asynchat.async_chat" title="asynchat.async_chat"><code class="xref py py-class docutils literal"><span class="pre">async_chat</span></code></a>读取HTTP请求。</span><span class="yiyi-st" id="yiyi-73">Web服务器可能会为每个传入的客户端连接创建<code class="xref py py-class docutils literal"><span class="pre">http_request_handler</span></code>对象。</span><span class="yiyi-st" id="yiyi-74">请注意最初通道终结符设置为与HTTP头末尾的空行相匹配并且一个标志表示正在读取这些头。</span></p><p><span class="yiyi-st" id="yiyi-75">一旦读取了头如果请求是POST类型指示输入流中存在更多数据那么<code class="docutils literal"><span class="pre">Content-Length:</span></code>头用于设置数字终止符,以读取来自通道的正确数量的数据。</span></p><p><span class="yiyi-st" id="yiyi-76">在将通道终结符设置为<code class="docutils literal"><span class="pre">None</span></code>之后,在所有相关输入已编组之后调用<code class="xref py py-meth docutils literal"><span class="pre">handle_request()</span></code>方法以确保忽略Web客户端发送的任何无关数据。</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">asynchat</span>
<span class="k">class</span> <span class="nc">http_request_handler</span><span class="p">(</span><span class="n">asynchat</span><span class="o">.</span><span class="n">async_chat</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sock</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> <span class="n">sessions</span><span class="p">,</span> <span class="n">log</span><span class="p">):</span>
<span class="n">asynchat</span><span class="o">.</span><span class="n">async_chat</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sock</span><span class="o">=</span><span class="n">sock</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">addr</span> <span class="o">=</span> <span class="n">addr</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sessions</span> <span class="o">=</span> <span class="n">sessions</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ibuffer</span> <span class="o">=</span> <span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">obuffer</span> <span class="o">=</span> <span class="n">b</span><span class="s2">""</span>
<span class="bp">self</span><span class="o">.</span><span class="n">set_terminator</span><span class="p">(</span><span class="n">b</span><span class="s2">"</span><span class="se">\r\n\r\n</span><span class="s2">"</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reading_headers</span> <span class="o">=</span> <span class="kc">True</span>
<span class="bp">self</span><span class="o">.</span><span class="n">handling</span> <span class="o">=</span> <span class="kc">False</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cgi_data</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">log</span> <span class="o">=</span> <span class="n">log</span>
<span class="k">def</span> <span class="nf">collect_incoming_data</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
<span class="sd">"""Buffer the data"""</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ibuffer</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">found_terminator</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">reading_headers</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reading_headers</span> <span class="o">=</span> <span class="kc">False</span>
<span class="bp">self</span><span class="o">.</span><span class="n">parse_headers</span><span class="p">(</span><span class="n">b</span><span class="s2">""</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ibuffer</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ibuffer</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">op</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span> <span class="o">==</span> <span class="n">b</span><span class="s2">"POST"</span><span class="p">:</span>
<span class="n">clen</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">getheader</span><span class="p">(</span><span class="s2">"content-length"</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">set_terminator</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">clen</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">handling</span> <span class="o">=</span> <span class="kc">True</span>
<span class="bp">self</span><span class="o">.</span><span class="n">set_terminator</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">handle_request</span><span class="p">()</span>
<span class="k">elif</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">handling</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">set_terminator</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span> <span class="c1"># browsers sometimes over-send</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cgi_data</span> <span class="o">=</span> <span class="n">parse</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">headers</span><span class="p">,</span> <span class="n">b</span><span class="s2">""</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ibuffer</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">handling</span> <span class="o">=</span> <span class="kc">True</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ibuffer</span> <span class="o">=</span> <span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">handle_request</span><span class="p">()</span>
</code></pre></div></div></div>