非阻塞 & IO多路复用
一、非阻塞
socket都是会阻塞的
在等待连接以及等待接收数据的时候进入一个阻塞状态
# 服务端
import socketphone = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
phone.bind(('127.0.0.1' , 8080))
phone.listen(5)# 设置非阻塞状态
phone.setblocking(False)# 保存客户端连接的对象
r_list = []while True:# 捕获阻塞异常try:# 获取等待客户端连接的对象conn , clinent = phone.accept()# 把获取到的连接对象进行保存r_list.append(conn)except BlockingIOError:del_list = []# 变量对象列表for i in r_list:try:# 接收客户端发送的数据data = i.recv(1024)print(data.decode('utf-8'))i.send(data)except BlockingIOError:continueexcept ConnectionResetError:i.close()del_list.append(i)for i in del_list:r_list.remove(i)
# 客户端
import socketphone = socket.socket(socket.AF_INET , socket.SOCK_STREAM)phone.connect(('127.0.0.1' , 8080))while True:msg = input('>>(q退出)').strip()if not msg:continueif msg == 'q':breakphone.send(msg.encode('utf-8'))data = phone.recv(1024)print(data.decode('utf-8'))phone.close()
二、IO多路复用
IO多路复用是通过一种机制,可以监视多个文件描述符,一旦有描述符就绪状态(写或者读),就行通知对应的程序进入与之相对应的操作。用于提升效率
r , w , e = select.select(rlist , wlist , errlist)rlist , wlist , errlist均是文件描述符
rlist :等待读就绪的文件描述
wlist :等待写就绪的文件描述
errlist :等待异常
import socket
import selectphone = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
phone.bind(('127.0.0.1' , 8080))
phone.listen(5)
# 设置非阻塞状态
phone.setblocking(False)read_list = [phone]
'''
read_list会存放自己的socket对象 ,对方的客户端连接对象
'''while True:r , w , e = select.select(read_list , [] , [])for i in r:if i is phone:# 获取新的客户端连接对象conn , addr = i.accept()read_list.append(conn)else:try:# 判断连接对象是否有数据发送data = i.recv(1024)print(addr)print(data.decode('utf-8'))except Exception:i.close()read_list.remove(i)continuei.send(data)
三、黏包
黏包问题就是:接收端不清楚发送端会发送多长的数据。
解决黏包:让发送端在发送数据之前,先返回一个数据长度 , 在发送数据