asyncore异步接字处理程序

源代码: Lib / asyncore.py

自版本3.6以后不推荐使用:请改用asyncio代替。


注意

此模块仅用于向后兼容。对于使用asyncio.

的新代码建议这个模块提供了编写异步socket服务客户端和服务器的基本基础结构.

只有两种方法让一个程序在一个处理器上做“一次多于一件事。”多线程编程是最简单和最流行的方法,但还有另一种非常不同的技术,让你几乎所有多线程的优点,实际上没有使用多个线程。如果你的程序主要是I / Obound,那真的很实用。如果您的程序受处理器限制,那么先发制人的预定线程可能就是您真正需要的。然而,网络服务器很少是处理器绑定的.

如果你的操作系统支持select()系统调用其I / Olibrary(几乎所有),然后您可以使用它来同时处理多个电信通道;当你的I / O在“背景”中发挥作用时做其他工作。虽然这个策略看起来很奇怪和复杂,特别是起初,它在很多方面比多线程编程更容易理解和控制。asyncore模块为您解决了许多难题,使得构建复杂的高性能网络服务器和客户端的任务变得轻而易举。对于“会话”应用程序和协议,同伴asynchat模块是无价的.

这两个模块背后的基本思想是创建一个或多个网络channels,类的实例asyncore.dispatcherasynchat.async_chat创建通道会将它们添加到一个全局地图中,如果你没有提供自己的loop()功能map.

一旦创建了初始通道,就调用loop()functionactivates channel service,一直持续到最后一个通道(包括在异步服务期间添加到地图中的任何通道)关闭.

asyncore.loop ( [timeout [, use_poll [, map [, count] ] ] ]
输入一个轮询循环,在计数通过或所有开放通道关闭后终止。所有参数都是可选的。count参数默认为None,导致循环仅在所有通道关闭时终止。timeout参数设置适当的select()poll()呼叫,以秒为单位;默认值为30秒。use_poll参数,如果为true,表示poll()应该用在select()(默认是False).

map参数是一个字典,其项目是要观看的频道。当频道关闭时,它们将从地图中删除。如果mapisomitted,使用全局地图。频道(的实例asyncore.dispatcher, asynchat.async_chat它可以在地图上自由混合.

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

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

事件 描述
handle_connect() 第一次读取或写入事件所暗示的
handle_close() 没有数据可用的读取事件所暗示
handle_accepted() 在listensocket上的read事件隐含

在异步处理过程中,每个映射的通道都是readable()writable()方法用于确定通道的socket是否应该添加到通道列表select() ed或poll() ed以进行读写事件.

那么,通道事件的集合大于基本套接字事件。可以在子类中重写的一整套方法如下:

handle_read
当异步循环检测到read()调用通道时调用socket会成功
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 ( )
在引发异常并且未以其他方式处理时调用。defaultversion打印出浓缩的追溯.
handle_accept ( )
当可以使用已发出connect()调用本地端点的新远程端点建立连接时,在侦听通道(被动开启器)上调用。版本3.2中已弃用;使用handle_accepted()代替。

版本3.2.

handle_acceptedsock, addr
当已经发布了一个新的远程端点与connect()呼叫本地端点。socknew接字对象,可以使用tosend并在连接上接收数据,addr是连接另一端套接字的地址.

版本3.2.

readable()
每次在异步循环周围调用,以确定是否应将achannel的套接字添加到可以发生读取事件的列表中。默认方法只返回True,表示默认情况下,所有频道都会对阅读事件感兴趣.
writable ()
每次在异步循环周围调用,以确定是否应将achannel的套接字添加到写入事件可能发生的列表中。默认方法只返回True,表示默认情况下,所有频道都会对书面活动感兴趣.

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

create_socket (family=socket.AF_INET, type=socket.SOCK_STREAM )
这与创建普通套接字相同,并将使用相同的选项进行创建。参考socket有关创建套接字的信息的文档.

改版3.3:familytype参数可以省略.

connectaddress
和普通的socket对象一样,address是连接主机的第一个元组,第二个是端口号.
senddata
发送data到插座的远端端点
recv//(buffer_size)
最多读buffer_size套接字远程端点的字节数。空字节对象意味着通道已从另一端关闭.

注意recv()可能会引发BlockingIOError,即使select.select()select.poll()已经报告了用于阅读的插座.

listen (backlog)
听听连接插座的情况。backlogarguments指定排队连接的最大数量,并且应该至少为1;最大值取决于系统(通常为5).
bindaddress
将插座绑定到address。套接字必须尚未绑定。(address的格式取决于地址族 – 有关详细信息,请参阅socket文档。)将套接字标记为可重用(设置SO_REUSEADDR选项),拨打dispatcher对象的set_reuse_addr()方法.
accept ()
接受连接。套接字必须绑定到一个地址并侦听连接。返回值可以是None或一对(conn, address)其中connnewsocket对象可用于在连接上发送和接收数据,而address是绑定到连接另一端的套接字的地址。当None返回时,表示连接没有发生,在这种情况下服务器应该忽略这个事件并继续听取进一步的传入连接.
close ()
关闭插座。套接字对象上的所有未来操作都将失败。远程端点将不再接收数据(在刷新排队数据之后)。套接字在收集垃圾时自动关闭.
class asyncore.dispatcher_with_send
dispatcher子类增加了简单的缓冲输出能力,对简单的客户端非常有用。对于更复杂的用法使用asynchat.async_chat.
class asyncore.file_dispatcher
file_dispatcher接受文件描述符或文件对象以及可选的map参数并将其包装以便与poll()一起使用或loop()功能。如果提供了一个文件对象或带有fileno()方法的任何东西,该方法将被调用并传递给file_wrapper构造函数

//Availability:Unix.

class asyncore.file_wrapper
file_wrapper接受整数文件描述符并调用os.dup() toduplicate句柄,以便原始句柄可以独立于file_wrapper关闭。这个类实现了足够的方法来模拟asocket使用file_dispatcher class

Availability: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服务器

这是一个使用的基本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()

评论被关闭。