自定义报头解决粘包问题

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()
客户端

 

以上是关于自定义报头解决粘包问题的主要内容,如果未能解决你的问题,请参考以下文章

峰哥解决粘包的方式

5.29—032—周三

No.30socketserver 模块

网络编程之基于UDP协议套接字

Netty框架之编解码机制二(自定义协议)

Netty框架之编解码机制二(自定义协议)