17.6. asyncore —异步套接字处理程序

源代码: Lib/asyncore.py


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

只有一种方法可以使程序在单个处理器上“一次完成一个以上的事情”。多线程编程是最简单,最流行的方法,但是还有另一种非常不同的技术,它使您几乎拥有多线程的所有优点,而无需实际使用多个线程。仅当您的程序很大程度上受 I/O 约束时,这才是切实可行的。如果您的程序受处理器限制,那么抢占式 sched 线程可能正是您 true 需要的。但是,Web Service 器很少受处理器限制。

如果您的 os 在其 I/O 库中支持select()系统调用(几乎所有方法都支持),则可以使用它同时处理多个通信通道。在“ I/O”发生在“后台”时进行其他工作。尽管这种策略看似奇怪且复杂,尤其是乍一看,但它在很多方面都比多线程编程更易于理解和控制。 asyncore模块为您解决了许多难题,使构建复杂的高性能 Web Service 器和 Client 端的任务变得很轻松。对于“会话式”应用程序和协议,配套的asynchat模块是无价的。

这两个模块的基本思想是创建一个或多个网络* channel ,它们是类asyncore.dispatcherasynchat.async_chat的实例。创建通道会将它们添加到全局 Map 中,如果您未为其提供自己的 map *,则由loop()函数使用。

创建初始通道后,调用loop()函数将激活通道服务,该操作将一直持续到最后一个通道(包括异步服务期间已添加到 Map 的任何通道)关闭为止。

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

Event Description
handle_connect() 由第一个读取或写入事件暗示
handle_close() 读事件所隐含,无可用数据
handle_accept() 由侦听套接字上的读取事件暗示

在异步处理期间,每个 Map 的通道的readable()writable()方法用于确定是否将通道的套接字添加到通道 3_ed 或poll()ed 的列表中以进行读取和写入事件。

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

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

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

请注意,即使select.select()select.poll()报告已准备好读取套接字,但recv()可能会passEAGAINEWOULDBLOCK引发socket.error

17.6.1. asyncore 示例基本 HTTPClient 端

这是一个非常基本的 HTTPClient 端,它使用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()

17.6.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()
首页