18.7。 asynchat
- 异步套接字命令/响应处理器¶
源代码: Lib / asynchat.py
注意
此模块仅用于向后兼容。对于新代码,我们建议使用asyncio
。
该模块建立在asyncore
基础设施上,简化了异步客户端和服务器,使其更容易处理其元素由任意字符串终止或长度可变的协议。asynchat
定义您的子类的抽象类async_chat
,提供collect_incoming_data()
和found_terminator()
它使用与asyncore
相同的异步循环,并且两种类型的通道asyncore.dispatcher
和asynchat.async_chat
可以自由混合通道映射。通常,在接收传入连接请求时,asyncore.dispatcher
服务器通道会生成新的asynchat.async_chat
通道对象。
- class
asynchat.
async_chat
¶ 此类是
asyncore.dispatcher
的抽象子类。要实际使用代码,必须将async_chat
作为子类,提供有意义的collect_incoming_data()
和found_terminator()
方法。可以使用asyncore.dispatcher
方法,虽然在消息/响应上下文中并不都有意义。像
asyncore.dispatcher
,async_chat
定义了在select()
调用后通过分析套接字条件生成的一组事件。一旦轮询循环已启动,事件处理框架调用async_chat
对象的方法,而对程序员没有动作。可以修改两个类属性,以提高性能,或者甚至可以节省内存。
-
ac_in_buffer_size
¶ 异步输入缓冲区大小(默认值
4096
)。
-
ac_out_buffer_size
¶ 异步输出缓冲区大小(默认值
4096
)。
与
asyncore.dispatcher
不同,async_chat
允许您定义生产者的先入先出队列(fifo)。生产者需要只有一个方法,more()
,它应该返回要在通道上传输的数据。生产者指示疲劳(,即)通过使其more()
方法返回空字节对象,它不包含更多数据)。此时,async_chat
对象从fifo中删除生产者,并开始使用下一个生产者(如果有的话)。当生产者fifo为空时,handle_write()
方法不执行任何操作。您使用通道对象的set_terminator()
方法来描述如何识别来自远程端点的传入传输的结束或重要断点。要构建一个有效的
async_chat
子类,输入方法collect_incoming_data()
和found_terminator()
必须处理通道异步接收的数据。方法如下所述。-
-
async_chat.
close_when_done
()¶ 将
None
推送到制片人fifo。当这个制片人从fifo弹出时,它导致通道被关闭。
-
async_chat.
collect_incoming_data
(data)¶ 用数据调用,保存任意数量的接收数据。必须重写的默认方法引发一个
NotImplementedError
异常。
-
async_chat.
discard_buffers
()¶ 在紧急情况下,该方法将丢弃保存在输入和/或输出缓冲器和生产者fifo中的任何数据。
-
async_chat.
found_terminator
()¶ 当传入数据流与
set_terminator()
设置的终止条件匹配时调用。必须重写的默认方法引发一个NotImplementedError
异常。缓冲的输入数据应该通过实例属性可用。
-
async_chat.
get_terminator
()¶ 返回通道的当前终结符。
-
async_chat.
push
(data)¶ 将数据推送到通道的fifo以确保其传输。这是所有你需要做的是让通道将数据写入网络,虽然可以在更复杂的方案中使用自己的生产者来实现加密和分块。
-
async_chat.
push_with_producer
(producer)¶ 获取生产者对象并将其添加到与通道相关联的生成者fifo。当所有当前推送的生产者已经耗尽时,通道将通过调用其
more()
方法来消耗该生产者的数据,并将数据发送到远程端点。
-
async_chat.
set_terminator
(term)¶ 设置要在通道上识别的终止条件。
term
可以是三种类型的值中的任何一种,对应于处理传入协议数据的三种不同方式。术语 描述 string 当在输入流中找到字符串时,将调用 found_terminator()
integer 当接收到指定数量的字符时,将调用 found_terminator()
None
该频道继续永远收集数据 注意,在调用
found_terminator()
之后,通道后面的任何数据都可用于读取。
18.7.1. asynchat示例¶
以下部分示例显示如何使用async_chat
读取HTTP请求。Web服务器可能会为每个传入的客户端连接创建http_request_handler
对象。请注意,最初,通道终结符设置为与HTTP头末尾的空行相匹配,并且一个标志表示正在读取这些头。
一旦读取了头,如果请求是POST类型(指示输入流中存在更多数据),那么Content-Length:
头用于设置数字终止符,以读取来自通道的正确数量的数据。
在将通道终结符设置为None
之后,在所有相关输入已编组之后调用handle_request()
方法,以确保忽略Web客户端发送的任何无关数据。
import asynchat
class http_request_handler(asynchat.async_chat):
def __init__(self, sock, addr, sessions, log):
asynchat.async_chat.__init__(self, sock=sock)
self.addr = addr
self.sessions = sessions
self.ibuffer = []
self.obuffer = b""
self.set_terminator(b"\r\n\r\n")
self.reading_headers = True
self.handling = False
self.cgi_data = None
self.log = log
def collect_incoming_data(self, data):
"""Buffer the data"""
self.ibuffer.append(data)
def found_terminator(self):
if self.reading_headers:
self.reading_headers = False
self.parse_headers(b"".join(self.ibuffer))
self.ibuffer = []
if self.op.upper() == b"POST":
clen = self.headers.getheader("content-length")
self.set_terminator(int(clen))
else:
self.handling = True
self.set_terminator(None)
self.handle_request()
elif not self.handling:
self.set_terminator(None) # browsers sometimes over-send
self.cgi_data = parse(self.headers, b"".join(self.ibuffer))
self.handling = True
self.ibuffer = []
self.handle_request()