自定义报头解决粘包问题
Posted 云烟成雨。
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义报头解决粘包问题相关的知识,希望对你有一定的参考价值。
什么是黏包问题:
首先黏包问题只会在基于TCP协议的socket编程中出现,出现的原因是:由于TCP是字节流协议,客户端在接受服务短发来的数据时,会把数据组织成数据流接收。若客户端的socket对象调用的recv(size)方法中的size值大于或小于服务端发送的数据的长度,都会使多个数据包合成一个包传送,造成数据的混乱,从而形成黏包。
解决方法是:自定义报头。中心思想是:服务端定制报头(对发送数据的描述信息),服务端在发送真正的数据之前,先向客户端发送报头,客户端接受到报头之后,先读取报头的内容,让客户端知道数据的长度,从而指定自身recv()方法中size的大小,解决黏包问题。
代码示例1:
1 import socket 2 import subprocess 3 import json 4 import struct 5 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 6 ip_port = (‘127.0.0.1‘,8855) 7 server.bind(ip_port) 8 server.listen(5) 9 while True: 10 con,add = server.accept() 11 print(con) 12 print(add) 13 while True: 14 try: 15 data_bytes = con.recv(1024) 16 if not data_bytes:break 17 cmd = subprocess.Popen(data_bytes.decode(‘utf-8‘),shell=True, 18 stdout=subprocess.PIPE, 19 stderr=subprocess.PIPE) 20 #从管道读出的数据都是bytes类型,因此在发送到客户端时不需要编码 21 std_out = cmd.stdout.read() 22 std_err = cmd.stderr.read() 23 data_size = len(std_out) + len(std_err) 24 #定制报头 25 head_dic = {‘data_size‘:data_size} 26 # 报头处理 27 head_str = json.dumps(head_dic) 28 head_bytes = head_str.encode(‘utf-8‘) 29 head_len = len(head_str) 30 head_size = struct.pack(‘i‘,head_len) 31 # 发送报头长度(发送4个字节) 32 con.send(head_size) 33 #发送报头数据 34 con.send(head_bytes) 35 # 发送数据 36 con.send(std_out) 37 con.send(std_err) 38 except Exception: 39 break 40 con.close() 41 server.close()
1 import socket 2 import struct 3 import json 4 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 5 ip_port = (‘127.0.0.1‘,8855) 6 client.connect(ip_port) 7 while True: 8 msg = input(‘>>>:‘) 9 if not msg:continue 10 client.send(msg.encode(‘gbk‘)) 11 #part 1 收报头长度 12 head_bytes = client.recv(4) 13 head_len = struct.unpack(‘i‘,head_bytes)[0] 14 #part 2 收报头数据 15 dic_bytes = client.recv(head_len) 16 head_str = dic_bytes.decode(‘gbk‘) 17 head_dic = json.loads(head_str) 18 data_size = head_dic[‘data_size‘] 19 print(data_size) 20 #part 3 收数据 21 #统计每次循环取数据的长度 22 recv_size = 0 23 #累计循环收到的数据 24 recv_bytes = b‘‘ 25 while recv_size < data_size : 26 data = client.recv(1024) 27 recv_size = recv_size + len(data) 28 recv_bytes = recv_bytes + data 29 print(recv_bytes.decode(‘gbk‘)) 30 client.close()
以上是关于自定义报头解决粘包问题的主要内容,如果未能解决你的问题,请参考以下文章