• 网络IO模型


    一、阻塞IO模型

    阻塞IO基于socket程序

     

    原理:

     

     

    ① recv接收数据时,不是直接接收数据,而是程序将系统调用的命令发送到操作系统

    ② 当操作系统收到接收数据的请求,若此时无数据,操作系统会继续等待,处于等待数据阶段(wait for data阶段),这个阶段相对漫长

    ③ 当数据来了,操作系统会拷贝数据(copy data 阶段),从内核copy到内存

    ④ 当操作系统copy结束后,程序就能获取到recv的数据

     

    阻塞IO模型都会经历两个阶段

    wait for data 阶段    阻塞

    copy data 阶段                   阻塞

    存在的问题:一旦阻塞不能执行其他的任务 

     

    二、非阻塞IO模型

    特点:

    ① 选择性阻塞,可以执行其他任务

    ② 没有并发编程的机制,是一个同步的程序

    ③ 由于非阻塞的特点,程序不会在某一个连接recv或者sk.accept上进行阻塞,由更多的时间来做信息的收发,用一条线程实现并发的效果

          

     

    ① 程序发起recv,进行系统调用

    ② 操作系统接收命令后,若此时无数据,操作系统会返回到程序

    ③ 当有数据时,操作系统从内核copy到内存里

    ④ 拷贝结束后,程序会接收到数据

     

    缺点:高速运行,占用太多的CPU导致资源浪费,给CPU造成了很大的负担

     

    程序模拟

    # 非阻塞IO模型
    
    import socket
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',9000))
    sk.setblocking(False)       # 设置socket server为非阻塞
    sk.listen()
    
    conn_lis = []               # 链接的列表
    del_lis = []                # 断开链接的列表
    while 1:
        try:
            conn,addr = sk.accept()
            conn_lis.append(conn)
        except BlockingIOError:
            for conn in conn_lis:
                try:
                    conn.send(b'hello')             
                    print(conn.recv(1024))
                except (NameError,BlockingIOError):pass
                except ConnectionResetError:                # 客户端端口连接后
                    conn.close()                            # 关闭链接
                    del_lis.append(conn)                    # 添加到断开链接的列表
            
            for del_conn in del_lis:                        # 从链接列表里删除断开的链接
                conn_lis.remove(del_conn)
            del_lis.clear()                                 # 清空断开链接的列表

     

    三、IO多路复用模型

    原理:非阻塞的情况下加上代理

    代理是IO多路复用机制提供的代理,操作系统提供IO多路复用的机制,提供了一个模块select

    select 没模块用来操作系统中的select(IO多路复用)机制

    select.select(rlist,wlist,xlist)    # 按位置传参,传入列表

    rlist       读

    wlist      写

    xlist       特殊的条件

     

    ① 程序有一个代理(代替conn),代理进行系统调用,向操作系统发出命令,询问是否有数据

    ② 此时操作系统没数据,操作系统一直等待数据,代理会一直阻塞

    ③ 当有数据来了,数据准备好了,通知被代理的对象,conn收到信息,conn发起recv

    ④ 此操作系统copy数据,操作系统进入copy数据阶段

    ⑤ copy完成,recv拿到数据

     

    程序

    import select
    import socket
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',9000))
    sk.setblocking(False)
    sk.listen()
    
    r_lis = [sk]        # 存的是socket对象
    while 1:
        r_l,_,_ = select.select(r_lis,[],[])    # 按位置参数,不需要的参数要传入空列表
        for item in r_l:
            if item is sk:                      # 判断是否有链接
                conn,addr = sk.accept()
                r_lis.append(conn)
            else:
                try:
                    print((item.recv(1024)).decode())      # conn有消息接收
                    item.send(b'hello')
                except ConnectionResetError:               # 客户端断开链接
                    item.close()                           # 关闭链接conn
                    r_lis.remove(item)    

     

    IO多路复用是操作系统的工具,模块 select、poll、epoll都是发挥代理的作用,进行监听。但在windows上只有select模块,而在mac/linux系统上,三种机制并存。

    select的底层是操作系统在做轮询,有监听对象个数的限制,并且随着监听对象的个数越来越多,效率越来越低

    poll 跟 select 一样,但监听的个数比 select 要多

    epoll 给每一个要监听的对象都绑定了一个回调函数,数据来了直接调用对象,不再受到个数增加而降低效率的影响

     

    sockserver 底层使用了IO多路复用 + threading线程实现的

    selectors模块,在不同的系统上进行IO多路复用机制的自动筛选

     

    IO多路复用的好处:多个conn使用一个代理,整体的程序显得不忙碌,既能实现并发,又能节省资源

     

    四、异步IO模型

    不需要做任何操作,直接发指令即可

    过程:程序发起信息,操作系统立即给反应,操作系统一直在监听,当数据来了,会直接将数据放到内存中去,程序可以直接去内存读取

    但是python暂时没有对应的模块去使用异步IO

    等待数据阶段和拷贝数据阶段都不需要用户处理
    所有的操作都由操作系统替你完成
    copy数据阶段,只有异步IO是不需要阻塞的

  • 相关阅读:
    c数据结构 顺序表和链表 相关操作
    查找字符串中是否存在指定的字符
    比较两人生日相差多少天
    十进制转化为二进制(栈算法)
    c数据结构栈的基本操作(字符逆序输出)
    Django笔记-登陆、注册(利用cookie实现)
    Django笔记-常见错误整理
    Django笔记-post与get方法相关出错记录
    Django笔记-登陆注册-1
    Django笔记-helloworld
  • 原文地址:https://www.cnblogs.com/st-st/p/9714408.html
Copyright © 2020-2023  润新知