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.dispatcher
,asynchat.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()