socket沾包问题
为什么会沾包
- 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)
- 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
注意:只有TCP有粘包现象,UDP永远不会粘包
自制报头解决沾包
服务端
- 把真实数据转换成bytes -->header_bytes
- 使用struct.pack('i',len(header_bytes)),生成一个固定长度的报头(4字节的bytes)
- 使用sendall(报头+ 真实数据的bytes) 返回数据给客户端
客户端
- 客户端先recv(4),接收报头信息
- 然后使用struct.unpach('i',报头)解包,获取真实数据的长度
- 使用recv(数据长度)接收数据
import json import struct from socket import * s=socket(AF_INET,SOCK_STREAM) s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) s.bind(('127.0.0.1',8081)) s.listen(5) while True: print('等待链接...') conn,addr=s.accept() while True: try: data=conn.recv(1024) dic = {'file':'hanqian','size':12345,'md5':'abcdefg'} dic_bytes = json.dumps(dic).encode('utf-8') # 字符串编码后是bytes类型 h_len = struct.pack('i',len(dic_bytes)) # h_len=4 报头固定长度 print('报头:',h_len) conn.send(h_len+dic_bytes) # 给客户端返回数据,对端会先接收4个字节获取报头,然后使用struct.unpack('i',报头)解包获取真实数据长度,然后调用s。recv except ConnectionResetError as e: break conn.close() # 关闭链接 s.close() # 关闭监听端口
import struct from socket import * s=socket(AF_INET,SOCK_STREAM) s.connect(('127.0.0.1',8081)) while True: msg=input('输入要发送的数据>>: ').strip() if not msg: continue 住 s.send(msg.encode('utf-8')) # 发送数据(只能发送字节类型) h_val = s.recv(4) # 先使用4个字节接收报头,获取的是打包后的值(bytes类型) print('报头:',h_val) data_size = struct.unpack('i',h_val)[0] # 解使用打包的值解包,data_size=真实数据大小(int类型) print('真实数据长度:',data_size) data=s.recv(data_size) # 接受数据 print(data.decode('gbk'))