标签:数据量 类型 byte dump lis 模块 数据打包 str 字典
这时候,接受不知道数据的限界,就没有办法正确的解析对方传输过来的限界。就才去了类似通信协议的解决方案,处理粘包问题。
简单解决问题的方法。根据当前需要发送的数据的大小传输数据的二进制长度先发送给客户端,在根据传输数据的长度来获取的真实的数据。
实现如下服务端
import socket,subprocess,struct server = socket.socket() server.bind(("127.0.0.1",54321)) server.listen(5) while True: client, addr = server.accept() while True: try: cmd = client.recv(1024).decode("utf-8")#接受命令 if not cmd: print("client closed") client.close() break p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) res = p.stdout.read()+p.stderr.read()#获得返回的数据 res_len =len(res)#整形形式的需要转换为固定长度的二进制形式。使用struct模块 bytes_len = struct.pack("i",res_len) client.send(bytes_len) client.send(res) except ConnectionResetError: print("客户端错误退出") client.close() break server.close()
客户端
import socket,struct client =socket.socket() client.connect(("127.0.0.1",54321)) while True: cmd = input(">>>:") if not cmd:continue client.send(cmd.encode("utf-8")) #获取数据的长度的二进制 bytes_len = client.recv(1024) #解压成为整形 res_len = struct.unpack("i",bytes_len)[0] #接受数据的方式 final_data=b"" #当前接受数据的长度计数器 data_len = 0 while data_len<res_len: res = client.recv(1024) final_data += res data_len += len(res) print(final_data.decode("gbk")) client.close()
其实我们还以定制更加复杂的数据头
可以字典形式表现,实现传输更加复杂文件,甚至可以进行校验
服务端
import socket,struct,json server = socket.socket() server.bind(("127.0.0.1",3333)) server.listen(5) while True: client,addr = server.accept() while True: try: ml = client.recv(1024).decode("utf-8")#模拟客户端请求报告 if not ml: client.close() break if ml != "1":continue #开始资质表头 filename = "总结" #计算文件bytes长度 file_len = 0 f = open(r"F:\Python_exe\day34\上午总结","rb") for line in f: line_len = len(line) file_len += line_len f.close() file_dict = {"filename":filename,"length":file_len} #将字典装换为json格式 json_dict = json.dumps(file_dict) #再json字符串转为bytes byte_dict = json_dict.encode("utf-8") #计算字典二进制的长度 head_len = len(byte_dict) #将长度打包成一个数据头 head = struct.pack("i", head_len) client.send(head) client.send(byte_dict) #标记内容完成 #传输正式内容 with open(r"F:\Python_exe\day34\上午总结","rb") as f: for line in f: client.send(line) except ConnectionResetError: print("连接错误连接") client.close() break
客户端
import socket,struct模块,json client = socket.socket() client.connect(("127.0.0.1",3333)) while True: ml = input(">>>:") if not ml:continue client.send(ml.encode("utf-8")) #获取字典的二进制 bytes_len = client.recv(4) #还原 head_len =struct模块.unpack(‘i‘, bytes_len)[0] #获取数据报头 bytes_dict = client.recv(head_len) #将bytes类型转化为json格式 json_dict = bytes_dict.decode("utf-8") #将字典json格式还原为成python的字典 file_dict=json.loads(json_dict) #获取文件的名称 filename = file_dict["filename"] #获取文件的传输长度 file_len = file_dict["length"] #打开文件追加写 f = open(filename,"ab") #当前接受长度 data_len = 0 while data_len<file_len: data = client.recv(1024) data_len += len(data) f.write(data) f.close() client.close() client.close()
解决粘包的方案 自定义报头
1.先用报头传输数据的长度
对于我们远程CMD程序来说 只要先传输长度就能解决粘包的问题
但是如果做得是一个文件上传下载 除了数据的长度 还需要传输文件的名字 md5等等信息
又该如何?
2.自定义复杂报头 完成发送一些额外的信息 例如文件名
1.将要发送的额外数据打包成一个字典
2.将字典转为bytes类型
3.计算字典的bytes长度 并先发送
4.发送字典数据
5.发送真实数据
标签:数据量 类型 byte dump lis 模块 数据打包 str 字典
原文地址:https://www.cnblogs.com/msj513/p/9911596.html