i/o模型
'''
默认情况下为阻塞I/O模型
阻塞I/O:I/O指的就是输入输出,I/O会出现等待的问题,程序会一直
存在问题:当执行的recv时,如果对象并没有发送数据,程序阻塞了,无法执行其他任务
解决方案:
多线程或者多进程,当客户端并发量非常大的时候,服务器可能就无法开启开启新的线程或者进程,如果不对数量 加以限制,服务器就崩溃了
线程池或进程池
协程:
默认情况下就是阻塞IO模型:
默认情况下就是阻塞IO模型
当执行recv时,如果对方没有数据到达,那么程序阻塞在原地
线程池, 有最大限制,不能无限的开线程
协程
非阻塞IO
非阻塞 即 即使遇到了IO操作,也不会阻塞在原地,会继续往下执行
server 是一个服务器socket对象
server.setblocking(Fasle)设置为非阻塞
每次读数据时,不一定有数据,为了能够及时处理数据,只能不停的询问,忙轮询
多路复用
异步IO
'''
网络IO中必经的两个阶段
非阻塞I/O模型
'''
阻塞IO模型在执行recv和accept都会经历wait_data
非阻塞IO即在执行recv和accep时,不会阻塞,可以继续往下执行
如何使用:
将severs.blocking(Flase)
'''
import socket
import time
server = socket.socket()
server.setblocking(False)
server.bind(('127.0.0.1',1688))
server.listen()
clients = []
msgs = []
try:
client,addr = server.accept()
clients.append(client)
except BlockingIOError as e:
print("还没有人链接过来")
time.sleep()#
for c in clients[:]:
try: # 可能这个客户端还没有数据过来
# 开始通讯任务
data = c.recv(2048)
if not data:
c.close()
clients.remove(c)
#c.send(data.upper()) # 如果碰巧缓存区满了 这个数据就丢失了
# 由于此处捕获了异常 所以应该单独来处理发送数据
msgs.append((c,data))
except BlockingIOError as e:
print("这个客户端还不需要处理.....",)
except ConnectionResetError:
# 断开后删除这个客户端
c.close()
clients.remove(c)
# 发送数据的操作
for i in msgs[:]:
try:
c,msg = i
c.send(msg.upper())
msgs.remove(i) # 如果发送成功! 删除这个数据
except BlockingIOError:
pass
多路复用I/O模型
'''
多路指的是:多个socket对象 一个socket就是一个传输通道
复用:意思是指使用同一个线程处理所有socket
原理:
在非阻塞IO模型中我们需要自己不断的询问操作系统是否有数据需要处理
多路复用,使用select来监测是否有socket可以被使用
'''
import socket
import select
server = socket.socket()
server.bind(('127.0.0.1', 1688))
server.listen()
# select最多检测1024个socket,超出直接报错,这是socket自身的问题,最终解决方案epoll
rlist = [server] # 将需要检测(是否可读recv)的socket对象放到该列表中
# accept也是一个读数据的操作,默认也会阻塞,也需要select检测
wlist = [] # 将需要检测(是否可写send)的socket对象放到该列表中
msgs = []
while True:
r_list, w_list, _ = select.select(rlist, wlist, []) # 会阻塞,等到有一个或者多个socket,可以被处理
print(r_list, w_list)
for soc in r_list:
if soc == server:
client, addr = server.accept()
rlist.append(client)
else:
try:
data = soc.recv(2048)
if not data:
soc.close()
rlist.remove(soc)
continue
msgs.append((soc,data))
except ConnectionResetError as e:
soc.close()
rlist.remove(soc)
print('这个客户端下线')
# client.recv()
for soc in w_list:
for i in msgs[:]:
if i[0] == soc:
soc.send(i[1])
msgs.remove(i)
wlist.remove(soc)