首页 > 代码库 > python之自定义异步IO客户端

python之自定义异步IO客户端

#!/usr/bin/env python# -*- coding: utf8 -*-# __Author: "Skiler Hao"# date: 2017/5/16 15:04import selectimport socketimport pprint"""自定义了异步IO模块利用非阻塞的socket,不等待连接是否成功,不等待请求的相应select模块,去监听创建的套接字,是否有准备写,准备读的"""class HttpResponse:    def __init__(self, response_data):        self.raw_data = response_data        self.data = str(response_data, encoding=utf-8)        self.Header = {}        self.GET = {}        self.BODY = {}        self.response_info = ‘‘        self.initialize()    def initialize(self):        header_data, body_data = self.data.split(\r\n\r\n, 1)        self.BODY = body_data        header_list = header_data.split(\r\n)        # print(header_list)        for header_item in header_list:            header_byte = header_item.split(:, 1)            if len(header_byte) == 2:                self.Header[header_byte[0]] = header_byte[1]            else:                self.response_info = header_byte    def __str__(self):        return self.response_infoclass HttpRequest:    """    对HttpRequest的简单封装,将socket,host和callback封装成一个对象    """    def __init__(self, sk, host, callback):        """        收到socket,host, callback回调函数,将其封装成HttRequest对象        :param sk:一个socket对象        :param host:主机名或者域名        :param callback:socket结束后的回调函数        """        self.socket = sk        self.host = host        self.callback = callback    def fileno(self):        """        select可以直接监听        定义一个fileno()并返回一个,可以将HttpRequest()对象直接放在select直接去轮训,监听        :return:fileno()文件描述符        """        return self.socket.fileno()class AsyncHttpClient:    """    异步Http客户端    """    def __init__(self):        self.conn = []        self.connection = []    def add_request(self, host, callback):        """        传过来一个host和callback,自动将其封装HttpRequest对象,然后将其加入到self.conn和self.connection中        :param host: 传过来一个host,一个回调函数callback        :param callback:        :return:        """        sk = socket.socket()        sk.setblocking(0)  # 创建一个非阻塞的socket        try:            sk.connect((host, 80))  # 这个socket去连指定的主机的80端口        except BlockingIOError as e:            pass        # 将socket,host,callback封装成一个对象        http_request = HttpRequest(sk, host, callback)        # 将对象追加到conn和connection        self.conn.append(http_request)        self.connection.append(http_request)    def run(self):        # 任务调用的接口        while True:            # 监听套接字的信号            # select(rlist,wlist,xlist)            # 三个列表,select分别监听 三个列表,rlist是否有读信号,wlist是否写信号,xlist是否有异常信号,最后是timeout            # 一旦有某个对象相应的信号,就将当前的当前的对象返回给对应的位置            rlist, wlist, xlist = select.select(self.conn, self.connection, self.conn, 0.05)            # 一旦有写信号            for w in wlist:                # 首次就是服务器,告知连接成功,你可以往里面写数据啦                # print(w.host,‘连接成功,赶紧写数据吧!‘)                # 在套接字赶紧写上我要获取你的首页                tpl = "GET / HTTP/1.0\r\nHost:%s\r\n\r\n" % (w.host,)                w.socket.send(bytes(tpl, encoding=utf-8))                # select就不用监听这个套接字是否有写入信号,直接移除掉                self.connection.remove(w)            # 一旦有读信号            for r in rlist:                # print(r.host,‘开始收到数据啦~~~‘)                rec_data = bytes()                while True:                    # 开始收数据,直到接收不到数据                    try:                        chunk = r.socket.recv(8096)  # 一次接受8096个字节的数据                        rec_data += chunk                    except BlockingIOError as e:                        break                # print(r.host,rec_data)                # 执行打包中的callback方法,将接收到数据传过去                r.callback(rec_data)                r.socket.close()                # 获取到相应的相应数据,就不在监听其是否有读数据                self.conn.remove(r)            if len(self.conn) == 0:                # 如果没有要监听是否有读信号的套接字,就可以跳出循环任务结束了                breakdef f1(rec_data):    response = HttpResponse(rec_data)    print(response.BODY)def f2(data):    print(输出到屏幕)# 定义一个字典列表,字典列表包含主机名和回调函数url_list = [    {host: www.baidu.com, callback: f1},    {host: cn.bing.com, callback: f1},    {host: www.cnblogs.com, callback: f1},]# 声明一个异步Asyncrequestclient = AsyncHttpClient()for item in url_list:    requestclient.add_request(item[host], item[callback])requestclient.run()

 

python之自定义异步IO客户端