# 黏包现象
# 本质: tcp协议是流式传输,信息与信息之间没有边界
# 为什么会造成黏包
# 合包机制: 在发送端,由于两条消息发送的间隔很短,且这两条消息本身很短, 在发送时被合并成一条消息
# 在接收端,由于接受不及时导致两条先后到达的信息在接收端黏在了一起
# 解决黏包问题 -- 自定义协议>> struct模块: 把2**31(2GB)以内的数字变成固定的4个字节
# 简单的形式
# 先发送数据的长度,再发送数据
# 相对规范并复杂的形式
# 先把所有想发送的数据信息放到字典里,
# 再发送字典的长度
# 再发送字典
# 最后发送内容
import os import json import struct import socket sk = socket.socket() sk.connect(('127.0.0.1', 9001)) filepath = input('请输入文件路径 :') filename = os.path.basename(filepath) # os.path.basename 通过文件的路径,得到文件名 filesize = os.path.getsize(filepath) # 得到文件的大小 dic = {'filename': filename, 'filesize': filesize} # 将文件名, 文件大小写进字典 str_dic = json.dumps(dic) # 将字典序列化成字符串形式的字典 bytes_dic = str_dic.encode('utf-8') # 将字符串形式的字典 转成 字节 len_dic = len(bytes_dic) # 得到 字节的长度 bytes_len = struct.pack('i', len_dic) # 用struck.pack() 将字节 转换成4位的字节 sk.send(bytes_len) # 发送得到的4位字节 sk.send(bytes_dic) # 发送字节 with open(filepath, 'rb') as f: content = f.read() # 以rb模式 读取到文件中的内容 sk.send(content) # 发送内容 sk.close() # 先发送字典的长度 # 再发字典 {'filename':xxxx,'filesize':xxxxx} # 再发文件内容
import json import struct import socket sk = socket.socket() sk.bind(('127.0.0.1', 9001)) sk.listen() conn, addr = sk.accept() num = conn.recv(4) # 接收4位字节 num = struct.unpack('i', num)[0] # 读取4位字节, 获得字典长度 str_dic = conn.recv(num).decode('utf-8') # 读取字典长度, 得到字符串形式的字典 dic = json.loads(str_dic) # 将字符串形式的字典反序列化, 得到字典 with open(dic['filename'], 'wb') as f: content = conn.recv(dic['filesize']) # 接收从客户端发来的, dic['filesize']这么大的文件内容 f.write(content) conn.close() sk.close()