在线文档教程

asyncore

asyncore — Asynchronous socket handler

源代码: Lib / asyncore.py

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

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

如果您的操作系统select()在其I / O库中支持系统调用(几乎全部都是这样),那么您可以使用它来一次处理多个通信通道; 在你的I / O发生在“背景”时做其他工作。尽管这种策略看起来很奇怪和复杂,特别是一开始,它比多线程编程在许多方面更易于理解和控制。该asyncore模块为您解决了许多棘手的问题,从而迅速构建复杂的高性能网络服务器和客户端。对于“会话式”应用程序和协议,伴随asynchat模块是非常宝贵的。

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

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

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

输入一个轮询循环,在计数通过或所有打开的通道关闭后终止。所有参数都是可选的。的计数参数默认为None,导致在环路,只有当所有的频道都被关闭终止。的超时参数设置为适当的超时参数select()poll()呼叫,以秒为单位; 默认值是30秒。该use_poll参数,如果属实,表明poll()应优先使用select()(默认为False)。

地图参数是一个字典,字典的项目是观看渠道。由于频道关闭,他们将从他们的地图中删除。如果地图被省略,则使用全局地图。信道(的实例asyncore.dispatcherasynchat.async_chat和亚类的化合物)可自由地在地图上混合。

class asyncore.dispatcher

dispatcher类是一个低级别的插座对象的薄包装。为了使它更有用,它有几个用于事件处理的方法,这些方法是从异步循环中调用的。否则,它可以被当作普通的非阻塞套接字对象。

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

事件描述
handle_connect()由第一次读取或写入事件所暗示
handle_close()方法隐含在没有可用数据的读取事件中
handle_accept()监听套接字上的读事件暗示了这一点

在异步处理期间,每个映射通道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()本地端点呼叫的新远程端点建立连接时,在监听通道(被动开启者)上调用。

readable()

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

writable()

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

另外,每个通道都委托或扩展了许多套接字方法。其中大部分与他们的套接字伙伴几乎完全相同。

create_socket(family, type)

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

connect(address)

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

send(data)

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

recv(buffer_size)

从套接字的远程端点读取大多数buffer_size字节。一个空字符串意味着该通道已从另一端关闭。

请注意,recv()可能会socket.error随着EAGAIN或者EWOULDBLOCK即使select.select()或者select.poll()已经报告套接字准备好读取而提高。

listen(backlog)

听取与插座的连接。的积压参数指定排队的最大连接数和应至少为1; 最大值取决于系统(通常为5)。

bind(address)

将套接字绑定到地址。套接字不能被绑定。(地址格式取决于地址族 - 请参阅socket文档以获取更多信息。)要将套接字标记为可重用(设置SO_REUSEADDR选项),请调用dispatcher对象的set_reuse_addr()方法。

accept()

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

close()

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

class asyncore.dispatcher_with_send

一个dispatcher子类,增加了简单的缓冲输出能力,对于简单的客户非常有用。用于更复杂的用法asynchat.async_chat

class asyncore.file_dispatcher

file_dispatcher接受一个文件描述符或文件对象以及一个可选的map参数,并封装它以便与poll()or loop()函数一起使用。如果提供了一个文件对象或任何一个fileno()方法,该方法将被调用并传递给file_wrapper构造函数。可用性:UNIX。

class asyncore.file_wrapper

file_wrapper接受一个整型文件描述符并调用os.dup()复制句柄,以便独立于file_wrapper关闭原始句柄。该类实现了足够的方法来模拟file_dispatcher该类使用的套接字。可用性:UNIX。

1. asyncore基本HTTP客户端示例

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

import asyncore, socket class HTTPClient(asyncore.dispatcher): def __init__(self, host, path): asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect( (host, 80) ) self.buffer = 'GET %s HTTP/1.0\r\n\r\n' % path 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()

2. asyncore示例基本回显服务器

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

import asyncore import socket 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(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((host, port)) self.listen(5) def handle_accept(self): pair = self.accept() if pair is not None: sock, addr = pair print 'Incoming connection from %s' % repr(addr) handler = EchoHandler(sock) server = EchoServer('localhost', 8080) asyncore.loop()