立即学习: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 + stderrconn.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 = 0data = 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.完整代码:在上一篇笔记的基础上修改一下即可