粘包问题以及解决方法
一、粘包问题
1、问题一:无法确认对方发送过来数据的大小,对数据接收有影响
server.py文件内容:
"""先启动套接字服务端
注意:
客户端一次发送,服务端先一次接收,再发送
"""import socket
import subprocess
server = socket.socket()
server.bind(("127.0.0.1", 9527))
server.listen(5)
while True:
conn, addr = server.accept()
print(addr)
while True:
try:
# 从内存中获取数据
data = conn.recv(1024)
if len(data) == 0:
continue
data = data.decode("utf-8")
if data == "q":
break
# 调用subprocess,对终端进行操作,并获取操作后正确或错误的结果
# 接收转码后的字符串
obj = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 将结果交给result变量
result = obj.stdout.read() + obj.stderr.read()
print(result.decode("gbk"))
# 将结果返回给客户端
conn.send(result)
except Exception as e:
print(e)
break
conn.close()
client.py文件内容:
"""启动服务端后再启动客户端
"""import socket
client = socket.socket()
client.connect(("127.0.0.1", 9527))
while True:
cmd = input("请输入服务端命令:")
client.send(cmd.encode("utf-8"))
data = client.recv(1024) # 这里只接受到1024字节数据,可以调整,但是对内存有影响
if len(data) == 0:
continue
if data == "q":
break
print(data.decode("gbk"))
server.py执行结果:
client.py执行结果:
2、问题二:在发送数据间隔短并且数据量小的情况下,会将所有数据一次性传入
server.py文件内容:
"""先启动套接字服务端
注意:
客户端一次发送,服务端先一次接收,再发送
"""import socket
server = socket.socket()
server.bind(("127.0.0.1", 9527))
server.listen(5)
conn, addr = server.accept()
data = conn.recv(1024)
print(data)
client.py文件内容:
"""启动服务端后再启动客户端
"""import socket
client = socket.socket()
client.connect(("127.0.0.1", 9527))
"""
发送三次请求,理论上结果应该是
b"hello"
b"hello"
b"hello"
"""client.send(b"hello")
client.send(b"hello")
client.send(b"hello")
server.py执行结果:
3、解决粘包问题(struct模块)
1、struct模块是什么
struct模块是一个python内置模块,他可以将固定长度的数据,打包成固定格式的长度
" i "模式:可以将数据打包成 4 个bytes
2、struct模块的作用
可以将真实数据,做成一个固定长度的报头,客户端发送给服务端,服务端可以接受报头,然后对报头进行解包,获取真实数据的长度,进行接收即可
3、struct模块的使用
import structdata
= b"11111111111111"# 打包制作报头
header = struct.pack("i", len(data))
print(header)
# 解包获取真实数据长度 ---> 得到一个元组,元组中第一个值是真实数据的长度
res = struct.unpack("i", header)[0]
print(res)
执行结果:
b"x0ex00x00x00"14
4、粘包问题解决方法
只要确认对方数据的大小(长度),根据大小进行接收即可解决
- 无论哪一端先发送数据(例 客户端先行发送数据)
- 客户端
- 先制作报头并发送 struct.pack()
- 发送真实数据
- 服务端:
- 接收报头,并解包获取真实数据长度 struct.unpack()
- 根据真实数据长度 接收真实数据
server.py文件内容:
import socketimport subprocessimport structserver
= socket.socket()server.bind((
"127.0.0.1", 8001))server.listen(
5)while True:conn, addr
= server.accept()# print(addr)while True:
try:
# 获取客户端传过来的报头
client_headers = conn.recv(4)
# 解包获取真实数据长度
data_len = struct.unpack("i", client_headers)[0]
# 准备接收真实数据
data = conn.recv(data_len)
if len(data) == 0:
continue
data = data.decode("utf-8")
if data == "q":
break
# 调用subprocess,对终端进行操作,并获取操作后正确或错误的结果
# 接收转码后的字符串
obj = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 将结果交给result变量
result = obj.stdout.read() + obj.stderr.read()
# 服务端做一个报头发送给客户端
server_headers = struct.pack("i", len(result))
# 传送报头数据
conn.send(server_headers)
# 待客户端确认长度后,发送真实数据返回给客户端
conn.send(result)
except Exception as e:
print(e)
break
conn.close()
client.py文件内容:
import socketimport structclient
= socket.socket()client.connect((
"127.0.0.1", 8001))while True:cmd
= input("请输入服务端命令:")cmd_bytes
= cmd.encode("utf-8")# 做一个报头client_headers = struct.pack("i", len(cmd_bytes))
# 想服务端传送报头
client.send(client_headers)
# 待服务端确认数据长度后,发送真实数据
client.send(cmd_bytes)
# 获取服务端的传过来的报头
server_headers = client.recv(4)
# 解包获取数据的真实长度
data_len = struct.unpack("i", server_headers)[0]
# 准备接受真实数据
data = client.recv(data_len)
if len(data) == 0:
continue
if data == "q":
break
print(data.decode("gbk"))
可自行测试。
以上是 粘包问题以及解决方法 的全部内容, 来源链接: utcz.com/z/530237.html