版本3.6以后不推荐使用:请asyncio
改用。
此模块提供了编写异步套接字服务客户端和服务器的基本基础结构。
只有两种方法让一个程序在一个处理器上做“一次不止一件事。”多线程编程是最简单和最流行的方法,但还有另一种非常不同的技术,它可以让你几乎没有多线程的所有优点,没有实际使用多线程。如果您的程序主要受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.dispatcher
,asynchat.async_chat
和亚类的化合物)可自由地在地图上混合。
类asyncore.
dispatcher
的dispatcher
类是一个低级别的插座对象的薄包装。为了使它更有用,它有一些事件处理方法,它们从异步循环中调用。否则,它可以被视为普通的非阻塞套接字对象。
在某些时间或某些连接状态触发低级别事件会告诉异步循环某些更高级别的事件已经发生。例如,如果我们要求套接字连接到另一个主机,我们就知道当套接字第一次变为可写时已经建立了连接(此时你知道你可以写信给它,期望成功)。隐含的更高级别事件是:
事件 | 描述 |
---|---|
handle_connect() | 由第一个读或写事件暗示 |
handle_close() | 由没有数据可用的读取事件隐含 |
handle_accepted() | 隐藏在侦听套接字上的读取事件 |
在异步处理期间,每个映射的通道readable()
和 writable()
方法用于确定是否应将通道的套接字添加到为读取和写入事件select()
编辑或 poll()
编辑的通道列表中。
因此,通道事件集大于基本套接字事件。可以在子类中重写的完整方法集如下:
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
(袜子,地址)
当已与已发出connect()
本地端点呼叫的新远程端点建立连接时,在侦听通道(被动开启器)上调用。sock是一个新的套接字对象,可用于在连接上发送和接收数据,addr是绑定到连接另一端的套接字的地址。
版本3.2中的新功能。
readable
()
每次在异步循环周围调用,以确定是否应将通道的套接字添加到可能发生读取事件的列表中。默认方法只返回True
,表示默认情况下,所有通道都会对读取事件感兴趣。
writable
()
每次在异步循环周围调用,以确定是否应将通道的套接字添加到可能发生写入事件的列表中。默认方法只返回True
,表示默认情况下,所有通道都会对写入事件感兴趣。
此外,每个通道都委托或扩展了许多套接字方法。其中大多数与其套接字伙伴几乎完全相同。
create_socket
(family = socket.AF_INET,type = socket.SOCK_STREAM )
这与创建普通套接字相同,并将使用相同的选项进行创建。socket
有关创建套接字的信息,请参阅文档。
在版本3.3中更改:可以省略族和类型参数。
connect
(地址)
与普通套接字对象一样,address是一个元组,其中第一个元素是主机要连接的,第二个元素是端口号。
send
(数据)
将数据发送到套接字的远程端点。
recv
(buffer_size )
从套接字的远程端点读取最多buffer_size字节。空字节对象意味着通道已从另一端关闭。
请注意,即使 或已报告套接字已准备好进行读取,recv()
也可能会引发此问题。BlockingIOError
select.select()
select.poll()
listen
(积压)
侦听对套接字的连接。的积压参数指定排队的最大连接数和应至少为1; 最大值取决于系统(通常为5)。
bind
(地址)
将套接字绑定到地址。套接字必须尚未绑定。(地址格式取决于地址族 - socket
有关详细信息,请参阅 文档。)要将套接字标记为可重用(设置SO_REUSEADDR
选项),请调用dispatcher
对象的set_reuse_addr()
方法。
accept
()
接受连接。套接字必须绑定到一个地址并侦听连接。返回值可以是None
一对或一对 ,其中conn是可用于在连接上发送和接收数据的新套接字对象,address是绑定到连接另一端的套接字的地址。当返回这意味着连接并没有发生,在这种情况下,服务器应该只是忽略此事件,并保持侦听进一步的连接。(conn,address)
None
close
()
关闭插座。将来对套接字对象的所有操作都将失败。远程端点将不再接收数据(刷新排队数据后)。套接字在垃圾回收时会自动关闭。
类asyncore.
dispatcher_with_send
一个dispatcher
子类,它添加了简单的缓冲输出功能,对简单客户端很有用。用于更复杂的使用asynchat.async_chat
。
类asyncore.
file_dispatcher
file_dispatcher接受文件描述符或文件对象以及可选的map参数,并将其包装以与poll()
或loop()
函数一起使用。如果提供了一个文件对象或带有fileno()
方法的任何东西 ,那么该方法将被调用并传递给 file_wrapper
构造函数。
可用性:Unix。
类asyncore.
file_wrapper
file_wrapper接受整数文件描述符并调用os.dup()
复制句柄,以便可以独立于file_wrapper关闭原始句柄。此类实现了足够的方法来模拟套接字以供file_dispatcher
类使用。
可用性:Unix。
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示例基本回显服务器
这是一个基本的echo服务器,它使用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()