解决数据传输粘包的问题
服务端
将数据分为6个阶段发送给客户端
- 将报头内容,制作成字典形式
- 将字典dumps为json字符串
- 把得到的json字符串,转换为二进制bytes
- 通过struct.pack把二进制bytes的json字符串计算出4个字节长度
- 发送报头 4个字节长度
- 发送数据
import socket
import subprocess
import struct
import json
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 在bing 之前添加; 用于端口重用,释放
phone.bind(("127.0.0.1",8080))
phone.listen(5)
print("server start....")
# 接收消息,和发送消息
while True:
conn,client_addr=phone.accept() # 重新建立连接
while True:
try:
cmd = conn.recv(1024)
print("客户端接收:",cmd.decode("utf-8"))
if not cmd:break # 针对linux 客户端如果断开后,服务端持续打印空
res = subprocess.Popen(cmd.decode("utf-8"),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout = res.stdout.read()
stderr = res.stderr.read()
# 制作报头
# header = struct.pack("i",len(stdout)+len(stderr)) # i 表示把长度打包成 4个 字节长度
header_dic = {"total_size":len(stdout)+len(stderr),"md5":None}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode("utf-8")
# 先把报头的长度 打包成 4个 字节长度 发送给客户端
conn.send(struct.pack("i",len(header_bytes)))
# 发送报头
conn.send(header_bytes)
conn.send(stderr)
conn.send(stdout)
except Exception: # 针对windows 如果客户端断开,服务端也断开
break
conn.close()
phone.close()
客户端
客户端接收数据
- 接收报头长度为struct.pack“i”大小为4个字节,固定长度
- 解析报头,取出真正数据报头的长度
- 根据数据报头的长度收取bytes字符串长度
- 提取报头字典
- 从字典中取出,数据的大小
- 循环接收数据
import socket
import struct
import json
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(("127.0.0.1",8080))
# phone.send("hello".encode("utf-8"))
while True:
cmd = input(">>:").strip()
if not cmd:continue
phone.send(cmd.encode("utf-8"))
# 接收报头长度,大小为 “i” 定义的4个字节
struct_res = phone.recv(4)
# 解析报头,取出报头长度
header_size = struct.unpack("i",struct_res)[0]
# 在收报头
header_bytes = phone.recv(header_size)
# 提取报头字典
head_json = header_bytes.decode("utf-8")
head_dic = json.loads(head_json)
# 取出loads后字典中的total_size的值
total_size = head_dic["total_size"]
# 根据 取出的 字符串长度,循环接收内容
recv_size = 0 # 初始接收字节数为空
data = b"" # 初始数据值为空
while recv_size < total_size:
recv_date = phone.recv(1024)
recv_size += len(recv_date)
data += recv_date
print("命令结果:", data.decode("gbk"))
phone.close()