粘包问题以及解决方法

python

一、粘包问题

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 struct

data = 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 socket

import subprocess

import struct

server = 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 socket

import struct

client = 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

回到顶部