IO模型
一. IO模型
模型就是解决某个问题的套路
IO问题:
输入输出
我要一个用户名用来执行登陆操作,问题用户名需要用户输入,输入需要耗时, 如果输入没有完成,后续逻辑无法继续,所以默认的处理方式就是 等
将当前进程阻塞住,切换至其他进程执行,等到按下回车键,拿到了一个用户名,再唤醒刚才的进程,将状态调整为就绪态
以上处理方案 就称之为阻塞IO模型
存在的问题:
当执行到recv时,如果对象并没有发送数据,程序阻塞了,无法执行其他任务
解决方案:
多线程或多进程,
当客户端并发量非常大的时候,服务器可能就无法开启新的线程或进程,如果不对数量加以限制 服务器就崩溃了
线程池或进程池
首先限制了数量 保证服务器正常运行,但是问题是,如果客户端都处于阻塞状态,这些线程也阻塞了
协程:
使用一个线程处理所有客户端,当一个客户端处于阻塞状态时可以切换至其他客户端任务
二.非阻塞IO模型
阻塞IO模型在执行recv 和 accept 时 都需要经历wait_data
非阻塞IO即 在执行recv 和accept时 不会阻塞 可以继续往下执行
如何使用:
将server的blocking设置为False 即设置非阻塞
存在的问题 :
这样一来 你的进程 效率 非常高 没有任何的阻塞
很多情况下 并没有数据需要处理,但是我们的进程也需要不停的询问操作系统 会导致CPU占用过高
而且是无意义的占用
案例:
import socket import time server = socket.socket() server.bind(("192.168.13.103",1688)) server.listen() server.setblocking(False) # 默认为阻塞 设置为False 表示非阻塞 # 用来存储客户端的列表 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 os import socket, select server = socket.socket() server.bind(("127.0.0.1", 1688)) server.listen() # 需要使用select # 参数1 rlist 里面存储需要被检测是否可读(是否可以执行recv)的socket对象 # 参数2 wlist 里面存储需要被检测是否可写(是否可以执行send)的socket对象 # 参数3 xlist 存储你需要关注异常条件 忽略即可 # 参数4 timeout 检测超时时间 一段时间后还是没有可以被处理的socket 那就返回空列表 # 返回值: 三个列表 # 1 已经有数据到达的socket对象 # 2 可以发送数据的socket对象 怎么可以发 缓冲区没有满 # 3 忽略.... rlist = [server, ] wlist = [] msgs = [] while True: r_list, w_list, _ = select.select(rlist, wlist, []) # 阻塞直到socket可读或是可写 # 处理可读的socket for i in r_list: if i == server: client,addr = server.accept() print('%s连接了服务器' % os.getpid()) rlist.append(client) else: try: data = i.recv(2048) if not data: raise ConnectionResetError() wlist.append(i) msgs.append((i,data)) except ConnectionResetError: print('%s与服务器断开连接'%os.getpid()) i.close() rlist.remove(i) if i in wlist:wlist.remove(i) # 处理可写的数据 for i in w_list: for msg in msgs[:]: if msg[0] == i: i.send(msg[1].upper()) msgs.remove(msg) rlist.remove(i)

浙公网安备 33010602011771号