TCP粘包问题
一、粘包问题
1、粘包问题
接收方:我不知道我要接收的数据的总长度
发送方:由于tcp协议的内部优化算法:会将数据量比较小的并且时间间隔比较短的数据一次性打包发送
2、如何解决
第一步:发送数据直接先告诉对方数据量的大小,让对方知道怎么接收你的数据。
第二步:利用struct模块定制我们自己的消息传输协议:制作字典报头
3、最终版本解决粘包问题
客户端:
①制作字典报头
②发送报头
③再发送字典
④再发你的真实数据
服务端:
①先收4个长度的报头
②解析报头,获取字典长度
③接收字典(反序列化) ——>> 获取字典里面所有信息
④接收真实数据
4、代码(简单版)
服务端:
客户端:
5、代码(终极版)
服务端:
客户端:
六、struct模块使用
import struct data = 'dfsafsagdsfgfafsdafsdafafryuio' # 服务端 res = struct.pack('i', len(data)) # 打包:把一个数据打包为长度固定为4 print(len(res)) # 4 print(res) # b'\x1e\x00\x00\x00' # 客户端 ret = struct.unpack('i', res)[0] # 解包:数据真实长度 print(ret) # 30
二、大文件上传(解决粘包问题代码)
①客户端
import socket, os, json, struct client = socket.socket() client.connect(('127.0.0.1', 8080)) # 文件大小 file_size = os.path.getsize(r'D:\Desktop\wendang.txt') # 文件名 file_name = '计算机五大.txt' # 然后定义一个字典 d = { 'file_name': file_name, 'file_size': file_size, 'msg': '成功上传' } # 定义好字典后,先去转一下json,然后encode data_bytes = json.dumps(d).encode('utf-8') # 制作字典的报头 header = struct.pack('i', len(data_bytes)) # 发送报头 client.send(header) # 发送字典 client.send(data_bytes) # 然后发送真实数据:打开文件,一行一行读取出来,一行一行的发送 with open(r'D:\Desktop\wendang.txt', 'rb') as f: for line in f: client.send(line)
②服务端
import socket, json, struct server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) while True: conn, addr = server.accept() while True: try: # 先接收报头 header = conn.recv(4) # 解析报头,获取字典长度 header_len = struct.unpack('i', header)[0] # 接收字典 header_bytes = conn.recv(header_len) header_dic = json.loads(header_bytes.decode('utf_8')) print(header_dic) # 打印字典 # 循环接收文件,存储到本地 file_size = header_dic.get('file_size') file_name = header_dic.get('file_name') recv_size = 0 # 文件操作 with open(file_name, 'wb') as f: while recv_size < file_size: # 循环接收 data = conn.recv(1024) f.write(data) recv_size += len(data) print(header_dic.get('msg')) # 文件上传成功后的提示信息 except ConnectionResetError: break conn.close()