粘包问题及解决方案

Posted zhangjinyi97

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了粘包问题及解决方案相关的知识,希望对你有一定的参考价值。

一、粘包问题
问题1: 无法确认对方发送过来数据的大小。

‘client.py‘

import socket

client = socket.socket()

client.connect(
(‘127.0.0.1‘, 9000)
)

while True:

cmd = input(‘客户端输入的内容: ‘)

client.send(cmd.encode(‘utf-8‘))

data = client.recv(19190)
print(len(data))
print(data.decode(‘gbk‘))
‘server.py‘

import socket
import subprocess

server = socket.socket()
server.bind((‘127.0.0.1‘,9000))
server.listen(5)

while True:
conn,addr = server.accept()
print(addr)
while True:
try:
cmd = conn.recv(10)
if len(cmd) == 0:
continue
cmd = cmd.decode(‘utf-8‘) #utf8
if cmd == ‘q‘:
break
#调用subprocess连接终端,对终端进行操作,并获取操作后正确或错误的结果
obj = subprocess.Popen(
#cmd接受的是解码后的字符串
cmd,shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
#结果交给result变量名
result = obj.stdout.read()+obj.stderr.read()
print(len(result))
print(result.decode(‘gbk‘)) #windows系统下默认编码gbk
#将结果返回给客户端
conn.send(result)

except Exception as e:
print(e)
break
conn.close()

问题2: 在发送数据间隔短并且数据量小的情况下,会将所有数据一次性发送。

‘client.py‘

import socket

client = socket.socket()

client.connect(
(‘127.0.0.1‘, 9000)
)

client.send(b‘hello‘)
client.send(b‘hello‘)
client.send(b‘hello‘)
‘server.py‘

import socket

server = socket.socket()

server.bind(
(‘127.0.0.1‘, 9000)
)

server.listen(5)

conn, addr = server.accept()

data = conn.recv(5)
print(data) # b‘hello‘

data = conn.recv(1024)
print(data) # b‘hello‘

data = conn.recv(1024)
print(data) # b‘hello‘
二、粘包问题的解决方案:
粘包问题的解决方案: 确认对方数据的大小。

这里需要用 struct模块

struct是什么?
是一个python内置的模块,它可以将固定长度的数据,打包成固定格式的长度。
固定格式:如 “ i ” 模式
i : 4

struct作用:
可以将真实数据,做成一个固定长度的报头,客户端发送给服务器,服务器可以接受报头,然后对报头进行解包,获取真实数据的长度,进行接收即可

import struct

data = b‘1111111111111111‘
print(len(data)) #16

#打包制作报头
header = struct.pack(‘i‘,len(data))
print(header) #b‘x10x00x00x00‘
print(len(header)) #4

#解包获取真实数据长度 --->得到一个元组,元组中第一个值是真实数据的长度
res = struct.unpack(‘i‘,header)[0]
print(res) #16

无论哪一端先发送数据

客户端
- 1) 先制作报头,并发送 (struct)
- 2) 发送真实数据

服务端:
- 1) 接收报头,并解包获取 真实数据长度
- 2) 根据真实数据长度 接收真实数据
recv(真实数据长度)

‘client.py‘

在这里插入代码片import socket
import struct

client = socket.socket()

client.connect(
(‘127.0.0.1‘, 9000)
)

while True:

cmd = input(‘客户端输入的内容: ‘)
cmd_bytes = cmd.encode(‘utf-8‘)

#做一个报头
header = struct.pack(‘i‘,len(cmd_bytes))
print(len(header))
client.send(header)

#待服务端确认长度后,发送真实数据长度
client.send(cmd_bytes)
#接受服务端的报头
headers = client.recv(4)

#解包,接受服务器返回的真实数据的长度
data_len = struct.unpack(‘i‘,headers)[0]
result = client.recv(data_len)

print(‘接受服务器返回的真实数据的长度‘,len(result))
print(result.decode(‘gbk‘))

 

 

# 问题2:
# import socket
#
# client = socket.socket()
#
# client.connect(
# (‘127.0.0.1‘, 9000)
# )
#
# client.send(b‘hello‘)
# client.send(b‘hello‘)
# client.send(b‘hello‘)

‘server.py‘

import socket
import subprocess
import struct

server = socket.socket()
server.bind((‘127.0.0.1‘,9000))
server.listen(5)

while True:
conn,addr = server.accept()
print(addr)
while True:
try:
#获取客户端传过来的报头
header = conn.recv(10)
#解包获取真实数据的长度
data_len = struct.unpack(‘i‘,header)[0]

#准备接受真实数据
cmd = conn.recv(data_len)

if len(cmd) == 0:
continue
cmd = cmd.decode(‘utf-8‘) #utf8
if cmd == ‘q‘:
break
#调用subprocess连接终端,对终端进行操作,并获取操作后正确或错误的结果
obj = subprocess.Popen(
#cmd接受的是解码后的字符串
cmd,shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
#结果交给result变量名
result = obj.stdout.read()+obj.stderr.read()
print(‘发送给服务端返回的真实数据的长度‘, len(result))
# print(result.decode(‘gbk‘)) #windows系统下默认编码gbk

# 做一个报头,返回给客户端
header = struct.pack(‘i‘, len(result))
print(len(header))
conn.send(header)

#将结果返回给客户端
conn.send(result)


except Exception as e:
print(e)
break
conn.close(
原文链接:https://blog.csdn.net/weixin_45816565/article/details/103410678

以上是关于粘包问题及解决方案的主要内容,如果未能解决你的问题,请参考以下文章

12.netty中tcp粘包拆包问题及解决方法

TCP粘包,拆包及解决方法

DIOCP之DEMO-粘包问题及解决

tcp协议下粘包问题的产生及解决方案

20 Apr 18 粘包问题及解决方法

python 网络编程-03 粘包问题及处理