mirror of
https://github.com/fofolee/uTools-Manuals.git
synced 2025-06-08 23:14:06 +08:00
39 lines
24 KiB
HTML
39 lines
24 KiB
HTML
<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></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></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> |