• day-39网络编程


    IO模型

      模型:就是解决某个问题的套路

      IO问题:

        输入输出

      当一个用户名用来执行登陆操作,问题用户名需要用户输入,输入需要耗时, 如果输入没有完成,后续逻辑无法继续,所以默认的处理方式就是 等

      然后将当前进程阻塞住,切换至其他进程执行,等到按下回车键,拿到了一个用户名,再唤醒刚才的进程,将状态调整为就绪态

      以上处理方案 就称之为阻塞IO模型

      存在的问题:   

        当执行到recv时,如果对象并没有发送数据,程序阻塞了,无法执行其他任务

      解决方案:

        1多线程或多进程,

        当客户端并发量非常大的时候,服务器可能就无法开启新的线程或进程,如果不对数量加以限制 服务器就崩溃了

        2线程池或进程池

        首先限制了数量 保证服务器正常运行,但是问题是,如果客户端都处于阻塞状态,这些线程也阻塞了

        3协程:

        使用一个线程处理所有客户端,当一个客户端处于阻塞状态时可以切换至其他客户端任务

    非阻塞IO模型

      阻塞IO模型在执行recv 和 accept 时 都需要经历wait_data

      非阻塞IO即 在执行recv 和accept时 不会阻塞 可以继续往下执行

      如何使用:

        将server的blocking设置为False 即设置非阻塞  

      存在的问题 :

        这样一来 你的进程 效率 非常高 没有任何的阻塞

        但很多情况下 并没有数据需要处理,但是我们的进程也需要不停的询问操作系统 会导致CPU占用过高

        而且是无意义的占用

    # 用来存储客户端的列表
    clients = []
    
    # 链接客户端的循环
    while True:
        try:
            client,addr = server.accept()   # 接受三次握手信息
            # print("来了一个客户端了.... %s" % addr[1])
            # 有人链接成功了
            clients.append(client)
        except BlockingIOError as e:
            # print("还没有人连过来.....")
            # time.sleep(0.5)
            # 服务你的客人去
            for c in clients[:]:
                try: # 可能这个客户端还没有数据过来
                    # 开始通讯任务
                    data = c.recv(2048)
                    c.send(data.upper())
                except BlockingIOError as e:
                    print("这个客户端还不需要处理.....",)
    
                except ConnectionResetError:
                    # 断开后删除这个客户端
                    clients.remove(c)
            print("=======================",len(clients))

    多路复用IO模型

    import socket
    import time
    import select
    
    
    server = socket.socket()
    server.bind(("127.0.0.1",1688))
    server.listen()
    # server.setblocking(False) # 默认为阻塞    设置为False 表示非阻塞
    
    """
    参数1   rlist   里面存储需要被检测是否可读(是否可以执行recv)的socket对象 
    参数2   wlist   里面存储需要被检测是否可写(是否可以执行send)的socket对象 
    参数3   xlist 存储你需要关注异常条件  忽略即可
    参数4   timeout  检测超时时间  一段时间后还是没有可以被处理的socket 那就返回空列表  
    返回值:  三个列表
    1    已经有数据到达的socket对象 
    2    可以发送数据的socket对象    怎么可以发 缓冲区没有满  
    3    忽略....
    """
    rlist = [server,]
    wlist = []
    
    # 要发送的数据和socket
    msgs = []
    while True:
        ras,was,_ = select.select(rlist,wlist,[])  # 阻塞直到socket可读或是可写
        # 处理可读的socket
        for s in ras:
            if s == server:
                client,addr = server.accept()
                rlist.append(client)
            else:
                try:
                    # 收数据
                    data = s.recv(2048)
                    if not data:
                        raise ConnectionResetError()
                    wlist.append(s)
                    # s.send(data.upper())
                    # 将要发送的数据和socket 保存起来
                    msgs.append((s,data))
                except ConnectionResetError:
                    s.close()
                    rlist.remove(s)
                    if s in wlist:wlist.remove(s)
    
        # 处理可写的socket
        for s in was:
            for msg in msgs[:]:
                if msg[0] == s:
                    s.send(msg[1].upper())
                    # 发送成功之后 删除已经无用的数据 并且需要将socket从wlist列表中删除
                    # 不删除会造成死循环 因为socket 一直处于可写状态
                    msgs.remove(msg)
                    wlist.remove(s)

     

     

     

  • 相关阅读:
    IDEA 运行junit单元测试方法
    IDEA 修改编码
    接口文档word版
    java 上传文件到七牛云中
    单例模式
    洛谷P3092 [USACO13NOV]没有找零No Change
    Codevs 1159 最大全0子矩阵
    洛谷P2733 家的范围 Home on the Range
    洛谷P2280 [HNOI2003]激光炸弹
    洛谷P2023 [AHOI2009]维护序列
  • 原文地址:https://www.cnblogs.com/klw1/p/11000137.html
Copyright © 2020-2023  润新知