开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第天,点击查看活动详情
一、非阻塞
socket都是会阻塞的
在等待连接以及等待接收数据的时候进入一个阻塞状态
# 服务端
import socket
phone = 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:
continue
except ConnectionResetError:
i.close()
del_list.append(i)
for i in del_list:
r_list.remove(i)
# 客户端
import socket
phone = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
phone.connect(('127.0.0.1' , 8080))
while True:
msg = input('>>(q退出)').strip()
if not msg:
continue
if msg == 'q':
break
phone.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 select
phone = 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)
continue
i.send(data)
三、黏包
黏包问题就是:接收端不清楚发送端会发送多长的数据。
解决黏包:让发送端在发送数据之前,先返回一个数据长度 , 在发送数据