Py修行路 socket + select 实现 异步IO模块

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Py修行路 socket + select 实现 异步IO模块相关的知识,希望对你有一定的参考价值。

对于异步IO请求的本质则是【非阻塞Socket】+【IO多路复用】,那我们是否可以自定义异步IO模块?

自定义一个插件,模块如下:

技术分享
import socket
import select

class Request(object):
    """
    select监听的是有变化的对象,当多个socket通信存在的话,当发生变化时,无法确定哪个是哪个。此时就需要唯一指定哪个通信处理的是什么数据!
    我们想到的办法是,再另创建一个类,用于接收当前的socket和信息,实例化唯一的对象!
    巧妙之处就在于唯一化的处理,生成的每个对象都是唯一的!!!
    """
    def __init__(self,sock,info):
    #初始化
        self.sock = sock   通信
        self.info = info   信息

    def fileno(self):  #转换成fileno对象
        return self.sock.fileno()


class NoBlockIO(object):
    def __init__(self):
        self.sock_list = []
        self.conns = []

    def add_request(self,req_info):
        """
        创建请求
         假设:req_info = {‘host‘: ‘www.baidu.com‘, ‘port‘: 80, ‘path‘: ‘/‘},
        :return:
        """
        sock = socket.socket()  #创建socket对象
        sock.setblocking(False) #设置为非阻塞
        
        #建立连接,因为是非阻塞状态,连接可能会出异常所以做异常处理。
        #此处一定要注意,连接的请求已发出!
        try:
            sock.connect((req_info[host],req_info[port]))
        except BlockingIOError as e:
            pass
        #实例化唯一的通信对象
        obj = Request(sock,req_info) #将生成的sock对象和信息列表传递到Request类,然后获取对应的文件句柄,信息保留到
        self.sock_list.append(obj) #将得到的对象添加到sock_list 通信列表中
        self.conns.append(obj)    #将得到的对象添加到conns 连接列表中

    def run(self):
        """
        开始事件循环,检测:连接成功?数据是否返回?
        注意此处操作的就全是Request类生成的对象!!!
        :return:
        """
        while True:
            # select.select([request对象,])
            r,w,e = select.select(self.sock_list,self.conns,[],0.05)
            
            # w,是否连接成功
            for obj in w:
                # 检查obj:request对象
                # socket, {‘host‘: ‘www.baidu.com‘, ‘port‘: 80, ‘path‘: ‘/‘},
                data = "GET %s http/1.1\\r\\nhost:%s\\r\\n\\r\\n" %(obj.info[path],obj.info[host]) #发送GET请求的信息
                obj.sock.send(data.encode(utf-8)) #发送字节数据
                self.conns.remove(obj) #然后在连接列表中删除这个对象,排除循环通信的可能
            
            # 数据返回,接收到数据
            for obj in r:
                response = obj.sock.recv(8096)  #接收返回的信息
                obj.info[callback](response) #指定对应对象执行回调函数,参数为返回的信息
                self.sock_list.remove(obj)  #在监听列表中移除这个对象

            # 所有请求已经返回
            if not self.sock_list: #所有请求都处理完,就退出循环
                break
NBIO

调用这个插件,使用插件里的方法:

技术分享
from .NBIO import NoBlockIO

    #自定义定义回调函数,对返回的信息进行处理(执行完毕之后,对数据进行什么操作)
    def done1(response):
        print(response)

    def done2(response):
        print(response)
    
    #准备执行的信息,域名,端口号,回调函数
    url_list = [
        {host: www.baidu.com, port: 80, path: /,callback: done1},
        {host: www.cnblogs.com, port: 80, path: /index.html,callback: done2},
        {host: www.bing.com, port: 80, path: /,callback: done2},
    ]
    
    #实例化一个对象
    noblockObj = NoBlockIO()
    
    #循环要处理的信息
    for item in url_list:
        noblockObj.add_request(item)  #为条信息创建请求

    noblockObj.run() #执行
执行脚本

 

慎重说明:必须知道和理解整个执行的流程!!!

以上是关于Py修行路 socket + select 实现 异步IO模块的主要内容,如果未能解决你的问题,请参考以下文章

Py修行路 Pandas 模块基本用法

Py修行路 Matplotlib 绘图及可视化模块

py python实现socket

继续修行Python基础总结(注释|变量)

select 实现多路复用IO的server_socket

基于select类型多路IO复用,实现简单socket并发