asyncore — 异步套接字处理程序 — Python 文档

来自菜鸟教程
Python/docs/3.9/library/asyncore
跳转至:导航、​搜索

asyncore — 异步套接字处理程序

源代码: :source:`Lib/asyncore.py`

自 3.6 版起已弃用:请改用 asyncio



笔记

该模块的存在只是为了向后兼容。 对于新代码,我们建议使用 asyncio


该模块提供了用于编写异步套接字服务客户端和服务器的基本基础结构。

只有两种方法可以让单个处理器上的程序“一次做不止一件事情”。 多线程编程是最简单和最流行的方法,但还有另一种非常不同的技术,它可以让您拥有多线程的几乎所有优点,而无需实际使用多线程。 只有当您的程序在很大程度上受 I/O 限制时,它才真正实用。 如果您的程序受处理器限制,那么抢占式调度线程可能是您真正需要的。 然而,网络服务器很少受处理器限制。

如果您的操作系统在其 I/O 库中支持 [X38X] 系统调用(并且几乎都支持),那么您可以使用它同时处理多个通信通道; 在您的 I/O 在“后台”进行时做其他工作。 尽管这种策略看起来很奇怪和复杂,尤其是一开始,它在很多方面比多线程编程更容易理解和控制。 asyncore 模块为您解决了许多难题,使构建复杂的高性能网络服务器和客户端的任务变得轻而易举。 对于“对话”应用程序和协议,配套的 asynchat 模块是无价的。

这两个模块背后的基本思想是创建一个或多个网络 通道 、类 asyncore.dispatcherasynchat.async_chat 的实例。 创建通道将它们添加到全局地图中,如果您没有提供自己的 地图 ,则由 loop() 函数使用。

一旦创建了初始通道,调用 loop() 函数激活通道服务,该服务一直持续到最后一个通道(包括在异步服务期间添加到地图的任何通道)是关闭。

asyncore.loop([timeout[, use_poll[, map[, count]]]])

进入一个轮询循环,该循环在计数通过或所有打开的通道都已关闭后终止。 所有参数都是可选的。 count 参数默认为 None,导致循环仅在所有通道都已关闭时终止。 timeout 参数为适当的 select()poll() 调用设置超时参数,以秒为单位; 默认值为 30 秒。 use_poll 参数,如果为真,则表示 poll() 应该优先于 select()(默认为 False) .

map 参数是一个字典,其项目是要观看的频道。 当通道关闭时,它们会从它们的地图中删除。 如果省略 map,则使用全局映射。 频道(asyncore.dispatcherasynchat.async_chat 及其子类的实例)可以在地图中自由混合。

class asyncore.dispatcher

dispatcher 类是一个围绕低级套接字对象的瘦包装器。 为了使它更有用,它有一些从异步循环调用的事件处理方法。 否则,它可以被视为一个普通的非阻塞套接字对象。

在某些时间或在某些连接状态下触发低级事件告诉异步循环某些高级事件已经发生。 例如,如果我们要求一个套接字连接到另一台主机,当套接字第一次变为可写时,我们就知道已经建立了连接(此时您知道您可以期望成功写入它) )。 隐含的更高级别的事件是:

事件

说明

handle_connect()

由第一个读或写事件暗示

handle_close()

由没有可用数据的读取事件暗示

handle_accepted()

由侦听套接字上的读取事件暗示

在异步处理过程中,每个映射通道的 readable()writable() 方法用于确定该通道的套接字是否应添加到通道列表 select()ed或 poll()ed 用于读取和写入事件。

因此,通道事件集大于基本套接字事件。 可以在您的子类中覆盖的全套方法如下:

handle_read()

当异步循环检测到通道套接字上的 read() 调用将成功时调用。

handle_write()

当异步循环检测到可以写入可写套接字时调用。 通常,此方法将实现必要的性能缓冲。 例如:

def handle_write(self):
    sent = self.send(self.buffer)
    self.buffer = self.buffer[sent:]
handle_expt()

当套接字连接有带外 (OOB) 数据时调用。 这几乎永远不会发生,因为 OOB 很少被支持并且很少使用。

handle_connect()

当主动开启者的套接字实际建立连接时调用。 例如,可能会发送“欢迎”横幅,或启动与远程端点的协议协商。

handle_close()

当套接字关闭时调用。

handle_error()

在引发异常且未以其他方式处理时调用。 默认版本打印压缩回溯。

handle_accept()

当可以与新的远程端点建立连接时,在侦听通道(被动开启器)上调用,该端点已为本地端点发出 connect() 调用。 在 3.2 版本中已弃用; 改用 handle_accepted()

自 3.2 版起已弃用。

handle_accepted(sock, addr)

当与新的远程端点建立连接时,在侦听通道(被动开启器)上调用,该端点已为本地端点发出 connect() 调用。 sock 是一个 new 套接字对象,可用于在连接上发送和接收数据,addr 是绑定到连接另一端套接字的地址.

3.2 版中的新功能。

readable()

每次围绕异步循环调用以确定是否应将通道的套接字添加到可以发生读取事件的列表中。 默认方法简单地返回 True,表示默认情况下,所有通道都会对读取事件感兴趣。

writable()

每次围绕异步循环调用以确定是否应将通道的套接字添加到可以发生写入事件的列表中。 默认方法简单地返回 True,表示默认情况下,所有通道都会对写入事件感兴趣。

此外,每个通道都委托或扩展了许多套接字方法。 其中大多数与它们的套接字伙伴几乎相同。

create_socket(family=socket.AF_INET, type=socket.SOCK_STREAM)

这与创建普通套接字相同,并且将使用相同的创建选项。 有关创建套接字的信息,请参阅 socket 文档。

3.3 版更改: familytype 参数可以省略。

connect(address)

与普通的套接字对象一样,address 是一个元组,第一个元素是主机要连接到的元素,第二个元素是端口号。

send(data)

data 发送到套接字的远程端点。

recv(buffer_size)

从套接字的远程端点最多读取 buffer_size 个字节。 空字节对象意味着通道已从另一端关闭。

请注意 recv() 可能会引发 BlockingIOError ,即使 select.select()select.poll() 已报告套接字准备阅读。

listen(backlog)

侦听与套接字的连接。 backlog 参数指定排队连接的最大数量,并且应该至少为 1; 最大值取决于系统(通常为 5)。

bind(address)

将套接字绑定到 地址 。 套接字必须尚未绑定。 (address 的格式取决于地址族 — 有关详细信息,请参阅 socket 文档。)将套接字标记为可重用(设置 SO_REUSEADDR选项),调用 dispatcher 对象的 set_reuse_addr() 方法。

accept()

接受连接。 套接字必须绑定到一个地址并侦听连接。 返回值可以是 None 或一对 (conn, address),其中 conn 是可用于在连接上发送和接收数据的 new 套接字对象, address 是绑定到连接另一端套接字的地址。 当返回 None 时,表示连接没有发生,在这种情况下,服务器应该忽略此事件并继续侦听进一步传入的连接。

close()

关闭插座。 套接字对象上的所有未来操作都将失败。 远程端点将不再接收数据(在刷新排队数据后)。 套接字在垃圾收集时会自动关闭。

class asyncore.dispatcher_with_send
一个 dispatcher 子类,它添加了简单的缓冲输出功能,对简单的客户端很有用。 对于更复杂的用法,请使用 asynchat.async_chat
class asyncore.file_dispatcher
file_dispatcher 接受一个文件描述符或 文件对象 以及一个可选的映射参数,并将其包装起来以与 poll()loop() 函数一起使用。 如果提供了一个文件对象或任何带有 fileno() 方法的东西,该方法将被调用并传递给 file_wrapper 构造函数。
class asyncore.file_wrapper
file_wrapper 接受一个整数文件描述符并调用 os.dup() 来复制句柄,以便可以独立于 file_wrapper 关闭原始句柄。 此类实现了足够的方法来模拟供 file_dispatcher 类使用的套接字。

asyncore 示例基本 HTTP 客户端

这是一个非常基本的 HTTP 客户端,它使用 dispatcher 类来实现其套接字处理:

import asyncore

class HTTPClient(asyncore.dispatcher):

    def __init__(self, host, path):
        asyncore.dispatcher.__init__(self)
        self.create_socket()
        self.connect( (host, 80) )
        self.buffer = bytes('GET %s HTTP/1.0\r\nHost: %s\r\n\r\n' %
                            (path, host), 'ascii')

    def handle_connect(self):
        pass

    def handle_close(self):
        self.close()

    def handle_read(self):
        print(self.recv(8192))

    def writable(self):
        return (len(self.buffer) > 0)

    def handle_write(self):
        sent = self.send(self.buffer)
        self.buffer = self.buffer[sent:]


client = HTTPClient('www.python.org', '/')
asyncore.loop()

asyncore 示例基本回显服务器

这是一个基本的回显服务器,它使用 dispatcher 类来接受连接并将传入的连接分派给处理程序:

import asyncore

class EchoHandler(asyncore.dispatcher_with_send):

    def handle_read(self):
        data = self.recv(8192)
        if data:
            self.send(data)

class EchoServer(asyncore.dispatcher):

    def __init__(self, host, port):
        asyncore.dispatcher.__init__(self)
        self.create_socket()
        self.set_reuse_addr()
        self.bind((host, port))
        self.listen(5)

    def handle_accepted(self, sock, addr):
        print('Incoming connection from %s' % repr(addr))
        handler = EchoHandler(sock)

server = EchoServer('localhost', 8080)
asyncore.loop()