解决粘包问题
时间:2019-09-13 17:28:04
收藏:0
阅读:207686
解决粘包问题
一、解决粘包问题方式一
问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据。
1.1 服务器
import socket
import subprocess
import struct
soc = socket.socket()
soc.bind(('127.0.0.1', 8001))
soc.listen(4)
while True:
print("等待客户端连接")
conn, addr = soc.accept()
print("有个客户端连接上:", addr)
while True:
try:
data = conn.recv(1024)
if len(data) == 0:
break
print(data)
obj = subprocess.Popen(data.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 执行结果为b格式, gbk编码(windows平台)
msg = obj.stdout.read()
"""
发送的时候需要把长度计算出来
头必须是固定的长度
选取出要发送数据的长度
"""
leng = len(msg)
# head是固定的四个字节
head = struct.pack('i', leng)
# 发送头
conn.send(head)
# 发送内容
conn.send(msg)
except Exception as e:
print(e)
break
conn.close()
soc.close()
1.2 客户端
import socket
import struct
soc = socket.socket()
soc.connect(('127.0.0.1', 8001))
while True:
in_s = input("请输入要执行命令:")
soc.send(in_s.encode('utf-8'))
head = soc.recv(4)
lengs = struct.unpack('i', head)[0]
count = 0
data_total = b""
while count < lengs:
if lengs < 1024:
# 如果接收的数据小于1024,直接接收数据的大小
data = soc.recv(lengs)
else:
# 如果接收的数据大于1024
if lengs - count > 1024:
# 总数据长度减去count(目前收到多少, count就是多少), 如果还大于1024,在收1024
data = soc.recv(1024)
else:
# 总数据长度减去count(目前收到多少,count就是多少), 如果小于1024, 只收剩下的部分即可
data = soc.recv(lengs- count)
data_total += data
count += len(data)
print(data_total.decode('gbk'))
缺点:
程序的运行速度远快于网络传输速度,所以在发送一段字节前,先用send去发送该字节流长度,这种方式会放大网络延迟带来的性能损耗
二、补充struct模块
2.1 简单实用
[
import struct
import json
# 'i'是格式
try:
obj = struct.pack('i', 1222222222223)
except Exception as e:
print(e)
obj = struct.pack('i', 1222)
print(obj, len(obj))
‘i‘ format requires -2147483648 <= number <= 2147483647
b‘\xc6\x04\x00\x00‘ 4
res = struct.unpack('i', obj)
print(res[0])
1222
三、解决粘包问题终结版
解决粘包问题的核心就是:为字节流加上自定义固定长度报头,报头中包含字节流长度,然后一次send到对端,对端在接收时,先从缓存中取出定长的报头,然后再取真实数据。
3.1 使用struct模块创建报头
import json
import struct
header_dic = {
'filename': 'a.txt',
'total_size':
111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223131232,
'hash': 'asdf123123x123213x'
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('utf-8')
print(len(header_bytes))
# 'i'是格式
obj = struct.pack('i', len(header_bytes))
print(obj, len(obj))
223
b‘\xdf\x00\x00\x00‘ 4
res = struct.unpack('i', obj)
print(res[0])
223
3.2服务端
import socket
import subprocess
import struct
soc = socket.socket()
soc.bind(('127.0.0.1', 8001))
soc.listen(4)
while True:
print("等待客户端连接")
conn, addr = soc.accept()
print("有个客户端连接上:", addr)
while True:
try:
data = conn.recv(1024)
if len(data) == 0:
break
print(data)
obj = subprocess.Popen(data.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 执行结果为b格式, gbk编码(windows平台)
msg = obj.stdout.read()
"""
发送的时候需要把长度计算出来
头必须是固定的长度
选取出要发送数据的长度
"""
leng = len(msg)
# head是固定的四个字节
head = struct.pack('i', leng)
# 发送头
conn.send(head)
# 发送内容
conn.send(msg)
except Exception as e:
print(e)
break
conn.close()
soc.close()
3.3 客户端
import socket
import struct
soc = socket.socket()
soc.connect(('127.0.0.1', 8001))
while True:
in_s = input("请输入要执行命令:")
soc.send(in_s.encode('utf-8'))
head = soc.recv(4)
lengs = struct.unpack('i', head)[0]
count = 0
data_total = b""
while count < lengs:
if lengs < 1024:
# 如果接收的数据小于1024,直接接收数据的大小
data = soc.recv(lengs)
else:
# 如果接收的数据大于1024
if lengs - count > 1024:
# 总数据长度减去count(目前收到多少, count就是多少), 如果还大于1024,在收1024
data = soc.recv(1024)
else:
# 总数据长度减去count(目前收到多少,count就是多少), 如果小于1024, 只收剩下的部分即可
data = soc.recv(lengs- count)
data_total += data
count += len(data)
print(data_total.decode('gbk'))
评论(0)