Python 常用模块struct

【一】介绍

  • struct 模块提供了一种处理二进制数据的方式
  • 它允许你使用类似于C语言的结构体的方式来打包(pack)和解包(unpack)数据
  • 这对于处理二进制文件、网络协议等场景非常有用

【二】使用

【1】打包

(1)讲解
FormatC TypePython typeStandard sizeNotes
xpad byteno value(7)
ccharbytes of length 11
bsigned charinteger1(1), (2)
Bunsigned charinteger1(2)
?_Boolbool1(1)
hshortinteger2(2)
Hunsigned shortinteger2(2)
iintinteger4(2)
Iunsigned intinteger4(2)
llonginteger4(2)
Lunsigned longinteger4(2)
qlong longinteger8(2)
Qunsigned long longinteger8(2)
nssize_tinteger(3)
Nsize_tinteger(3)
e(6)float2(4)
ffloatfloat4(4)
ddoublefloat8(4)
schar[]bytes(9)
pchar[]bytes(8)
Pvoid*integer(5)
(2)代码演示
  • python基础数据类型单独打包
import struct

int_value = 123156456
float_value = 4561.1123
bool_value = True


# 整型打包以后占用四个字节
int_struct = struct.pack('i', int_value)
print(int_struct, len(int_struct))

# 浮点型打包以后占用四个字节
float_struct = struct.pack('f', float_value)
print(float_struct, len(float_struct))

# 布尔型打包以后占用四个字节
bool_struct = struct.pack('?', bool_value)
print(bool_struct, len(bool_struct))

  • python字符串数据类型打包
import struct

str_value = "da456q1"

# 字符串格式需要转换成字节格式才可以打包,并且还需要提供字符串的长度,默认为1
# 提供的长度小于实际字符串的长度将打包部分数据,造成打包不完整
str_struct = struct.pack('7s', str_value.encode("utf8"))
print(str_struct, len(str_struct))
  • python基础数据类型一次性打包
    • 注意:fmt格式的顺序要和*v的顺序一致
import struct

int_value = 123156456
float_value = 4561.1123
bool_value = True
str_value = "da456q1"

# 一次打包多个
all_struct = struct.pack('i f ? 2s', int_value, float_value, bool_value, str_value.encode("utf8"))
print(all_struct, len(all_struct))

【2】解包

(1)讲解
  • struct.unpack(fmt, v1, v2......)
  • 作用:
    • fmt是格式字符串,需要知道打包的格式
    • v1,v2,…是待打包的数据
    • 解包以后得到一个元组
(2)代码演示
  • 单独数据解包
    • 返回元组,数据在元组第一个位置
import struct

int_struct = struct.pack('i', 123156456)
float_struct = struct.pack('f', 4561.1123)
bool_struct = struct.pack('?', True)
str_struct = struct.pack('7s', "da456q1".encode("utf8"))

# 解包后类型正常
int_res = struct.unpack("i", int_struct)
print(int_res, type(int_res[0]))

float_res = struct.unpack("f", float_struct)
print(float_res, type(float_res[0]))

bool_res = struct.unpack("?", bool_struct)
print(bool_res, type(bool_res[0]))

str_res = struct.unpack("7s", str_struct)
print(str_res, type(str_res[0]))
  • 混合数据解包
    • 按照打包顺寻返回一个元组
import struct

int_value = 123156456
float_value = 4561.1123
bool_value = True
str_value = "da456q1"

all_struct = struct.pack('i f ? 7s', int_value, float_value, bool_value, str_value.encode("utf8"))

res = struct.unpack('i f ? 7s', all_struct)
print(res)
# (123156456, 4561.1123046875, True, b'da456q1')

【三】应用

  • 问题:

    • 在socket模块的TCP协议传输数据中

    • 由于接收方不知道将要收到多大的数据,而导致数据读取可能不完整

    • 出现粘包问题,struct模块就可以用来解决这个问题

  • 解决办法:

    • 在每次发送数据之前就行数据大小计算
    • 计算的结果(长度)通过struct计算得到一个四字节的字节流
    • 通过发送这个固定大小的字节流
    • 接收端可以知道将要收到的数据的大小
    • 保证了可以将数据完整读出
# 服务端
import socket
import struct

# 1320KB的数据内容
big_data = ("重要信息" * 110).encode("utf8")
data_size = len(big_data)
data_size_struct = struct.pack("i", data_size)

# 创建socket对象
server = socket.socket()
server.bind(("localhost", 5656))
server.listen()
conn, addr = server.accept()

# 先发送大小数据
conn.send(data_size_struct)
# 发送大数据包
conn.send(big_data)

# 关闭
conn.close()
server.close()
# 客户端
import socket
import struct

client = socket.socket()
client.connect(("localhost", 5656))

# 读取大小文件
head = client.recv(4)
total = struct.unpack("i", head)[0]

# 根据大小接收数据
have = 0
data = bytes()
while have < total:
    data += client.recv(1024)
    have += 1024

print(data.decode("utf8"))

client.close()
  • 18
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值