立即学习:https://edu.csdn.net/course/play/24458/296244?utm_source=blogtoedu
粘包现象解决(终极版)
1.简单版的问题所在
1)报头信息不一定只是包含着命令执行结果的字节数长度,在文件传输的时候也可能包含文件名等,这时候就需要用到字典来将文件的相关信息进行封装
2)struct模块中struct.pack('l',数据长度),这个数据长度是有限制的,当发送的文件的字节数长度超过时,就会出现错误!
2.知识点
1)字典转为bytes类型:首先使用json.dumps(dict)将字典序列化为json字符串,然后使用.encode('utf-8')对json字符串进行编码成bytes类型
2)bytes类型解析为字典:首先对bytes进行解码成json字符串,然后将json字符串反序列为字典即可(json.loads(json字符串))
3.关键代码
'''
服务端
'''
......
#2处理命令,执行命令并且获得命令得到的结果
obj = subprocess.Popen(cmd.decode('utf-8'),shell=True,
stdout=subprocess.PIPE,#将正确运行命令得到的结果传给管道stdout中
stderr=subprocess.PIPE)#将没有正确运行命令得到的返回信息存放在stderr管道中
stdout = obj.stdout.read()
stderr = obj.stderr.read()
total_size = len(stderr + stdout)
#1)制作包含文件名和文件大小的文件头,用字典实现
headers_dict = {
"filename":"nianbao",
"filedata":"2020/03/09",
"total_size":total_size
}
#2)将字典先序列化成惊悚字符串,再转为bytes类型文件头
headers_json = json.dumps(headers_dict)
#3)获取bytes类型的长度
headers_bytes = headers_json.encode('utf-8')
headers_size = len(headers_bytes)
#4)将bytes类型文件头长度定制为固定长度的报头
header = struct.pack('i',headers_size)
#5)向客户端发送报头
conn.send(header)
#6)向客户端发送包含文件信息的字典
conn.send(headers_bytes)
#7)向客户端发送真实命令执行的结果
data = stdout + stderr
conn.send(data)
......
'''
客户端
'''
......
#4、接收服务器返回来的数据recv()
#1)先接收由服务器返回来的报头,报头是固定长度的,因此取前面4字节的数据即为报头
header = phone.recv(4)#返回的是一个对象
#2)解析报头,得到bytes类型的文件头长度
obj_truple = struct.unpack('i',header)#返回的是一个元组
headers_bytes_size = obj_truple[0]#取元组第一个元素即为总字节数
#3)接收bytes类型的文件头数据
headers_bytes = phone.recv(headers_bytes_size)
#4)将bytes类型的文件头数据反序列化成字典
headers_json = headers_bytes.decode('utf-8')
headers_dict = json.loads(headers_json)
#5)从字典中取出字命令执行结果字节总长度
total_size = headers_dict['total_size']
#6)接收返回的数据
recv_size = 0
data = b''
while recv_size < total_size:
recv_data = phone.recv(1024)#接收小于1024bytes的数据
recv_size += len(recv_data)
data += recv_data
#7)打印字典并且打印返回的数据
print(headers_dict)
print('服务器返回来的数据:',data.decode('gbk'))
print('*'*50)
......
4.完整代码:在上一篇笔记的基础上修改一下即可
作者:python_AI_fans