python struct pack解析_Python struct 详解

最近在学习python网络编程这一块,在写简单的socket通信代码时,遇到了struct这个模块的使用,当时不太清楚这到底有和作用,后来查阅了相关资料大概了解了,在这里做一下简单的总结。

了解c语言的人,一定会知道struct结构体在c语言中的作用,它定义了一种结构,里面包含不同类型的数据(int,char,bool等等),方便对某一结构对象进行处理。而在网络通信当中,大多传递的数据是以二进制流(binary data)存在的。当传递字符串时,不必担心太多的问题,而当传递诸如int、char之类的基本数据的时候,就需要有一种机制将某些特定的结构体类型打包成二进制流的字符串然后再网络传输,而接收端也应该可以通过某种机制进行解包还原出原始的结构体数据。python中的struct模块就提供了这样的机制,该模块的主要作用就是对python基本类型值与用python字符串格式表示的C struct类型间的转化(This module performs conversions between Python values and C structs represented as Python strings.)。stuct模块提供了很简单的几个函数,下面写几个例子。

1、基本的pack和unpack

struct提供用format specifier方式对数据进行打包和解包(Packing and Unpacking)。例如:

import struct

import binascii

values = (1, 'abc', 2.7)

s = struct.Struct('I3sf')

packed_data = s.pack(*values)

unpacked_data = s.unpack(packed_data)

print 'Original values:', values

print 'Format string :', s.format

print 'Uses :', s.size, 'bytes'

print 'Packed Value :', binascii.hexlify(packed_data)

print 'Unpacked Type :', type(unpacked_data), ' Value:', unpacked_data

输出:

Original values: (1, 'abc', 2.7)

Format string : I3sf

Uses : 12 bytes

Packed Value : 0100000061626300cdcc2c40

Unpacked Type :   Value: (1, 'abc', 2.700000047683716)

代码中,首先定义了一个元组数据,包含int、string、float三种数据类型,然后定义了struct对象,并制定了format‘I3sf’,I 表示int,3s表示三个字符长度的字符串,f 表示 float。最后通过struct的pack和unpack进行打包和解包。通过输出结果可以发现,value被pack之后,转化为了一段二进制字节串,而unpack可以把该字节串再转换回一个元组,但是值得注意的是对于float的精度发生了改变,这是由一些比如操作系统等客观因素所决定的。打包之后的数据所占用的字节数与C语言中的struct十分相似。定义format可以参照官方api提供的对照表:

2、字节顺序

另一方面,打包的后的字节顺序默认上是由操作系统的决定的,当然struct模块也提供了自定义字节顺序的功能,可以指定大端存储、小端存储等特定的字节顺序,对于底层通信的字节顺序是十分重要的,不同的字节顺序和存储方式也会导致字节大小的不同。在format字符串前面加上特定的符号即可以表示不同的字节顺序存储方式,例如采用小端存储 s = struct.Struct(‘

3、利用buffer,使用pack_into和unpack_from方法

使用二进制打包数据的场景大部分都是对性能要求比较高的使用环境。而在上面提到的pack方法都是对输入数据进行操作后重新创建了一个内存空间用于返回,也就是说我们每次pack都会在内存中分配出相应的内存资源,这有时是一种很大的性能浪费。struct模块还提供了pack_into() 和 unpack_from()的方法用来解决这样的问题,也就是对一个已经提前分配好的buffer进行字节的填充,而不会每次都产生一个新对象对字节进行存储。

import struct

import binascii

import ctypes

values = (1, 'abc', 2.7)

s = struct.Struct('I3sf')

prebuffer = ctypes.create_string_buffer(s.size)

print 'Before :',binascii.hexlify(prebuffer)

s.pack_into(prebuffer,0,*values)

print 'After pack:',binascii.hexlify(prebuffer)

unpacked = s.unpack_from(prebuffer,0)

print 'After unpack:',unpacked

输出:

Before : 000000000000000000000000

After pack: 0100000061626300cdcc2c40

After unpack: (1, 'abc', 2.700000047683716)

对比使用pack方法打包,pack_into 方法一直是在对prebuffer对象进行操作,没有产生多余的内存浪费。另外需要注意的一点是,pack_into和unpack_from方法均是对string buffer对象进行操作,并提供了offset参数,用户可以通过指定相应的offset,使相应的处理变得更加灵活。例如,我们可以把多个对象pack到一个buffer里面,然后通过指定不同的offset进行unpack:

import struct

import binascii

import ctypes

values1 = (1, 'abc', 2.7)

values2 = ('defg',101)

s1 = struct.Struct('I3sf')

s2 = struct.Struct('4sI')

prebuffer = ctypes.create_string_buffer(s1.size+s2.size)

print 'Before :',binascii.hexlify(prebuffer)

s1.pack_into(prebuffer,0,*values1)

s2.pack_into(prebuffer,s1.size,*values2)

print 'After pack:',binascii.hexlify(prebuffer)

print s1.unpack_from(prebuffer,0)

print s2.unpack_from(prebuffer,s1.size)

输出:

Before : 0000000000000000000000000000000000000000

After pack: 0100000061626300cdcc2c406465666765000000

(1, 'abc', 2.700000047683716)

('defg', 101)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/543091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux sudo 版本,Linu下如何升级当前sudo版本

Sudo 的全称是“superuserdo”,它是Linux系统管理指令,允许用户在不需要切换环境的前提下以其它用户的权限运行应用程序或命令,通常是以 root 用户身份运行命令,以减少 root 用户的登录和管理时间,同时提高安全性。该漏…

LaTeX技巧205:使用split输入多行公式技巧

我们在输入多行公式的时候,split,array,multiline,align,aligned等等都是我们可以选用的环境,这里介绍split的使用方法。演示效果图:演示代码:\documentclass{article}\pagestyle{em…

python改变列的数据类型_python – Pandas:更改列的数据类型

您可以使用pd.to_numeric(在版本0.17中引入)将列或Series转换为数字类型。该函数还可以使用apply应用于DataFrame的多个列。重要的是,该函数还接受一个错误关键字参数,它允许您强制非数字值为NaN,或者简单地忽略包含这些值的列。示例使用如下…

linux纯内核直接用吗,Linux:为啥内核有的变量没有初始化就敢直接使用?

一、问题为啥内核有的变量没有初始化就敢直接使用?二、分析看上图,其中的5747行的变量nid的确没有定义,就直接使用了,这么做没有问题吗?其实大家仔细看一下,5765行是一个宏,到内核源码去找该宏的…

mysql主从复制实践之单数据库多实例

1.主从复制数据库实战环境准备MySQL主从复制实践对环境的要求比较简单,可以是单机单数据库多实例的环境,也可以是两台服务器之间,每台服务器都部署一个独立的数据库的环境。本文以单机数据库多实例的环境进行实践。2.主从复制服务器角色定义序…

sdr 软件_【火腿专题】购买软件定义无线电(SDR)还是传统无线电台?追求欲望无止境...

软件定义无线电与传统无线电选择作者:Onno VK6FLAB有一段时间,我一直在解释软件无线电(SDR)的一些内部工作方式是如何运作的,以便深入了解原因和方法的细节。这种探索是在一个新世界的背景下进行的,在这个世界里,有无数…

linux文本运行层次,Linux基础知识之---文件系统层级结构

#Linux基础知识之---文件系统层级结构(Linux系统)[基础知识,文件系统,层级结构,FHS]一切皆文件: 在Linux中,无论是目录、配置、cpu、内存、键盘、鼠标、或者运行中的系统及内核、甚至临时缓存也都有对应的文件。“一切…

python的format函数如何理解_python format函数的使用

转载自:http://www.cnblogs.com/kaituorensheng/p/5709970.htmlpython自2.6后,新增了一种格式化字符串函数str.format(),威力十足,可以替换掉原来的%注:以下操作版本是python2.7映射示例语法通过{} 和 : 替换 %通过位…

Linux查询root环境变量,linux环境变量和查看方法

linux环境变量和查看方法1. 显示环境变量HOME[rootlocalhost ~]# echo $HOME/root2. 设置一个新的环境变量hello[rootlocalhost ~]# export HELLO"hello world"[rootlocalhost ~]# echo $HELLOhello world附:修改已存在的环境变量[rootlocalhost ~]# HELL…

服务器搭建-Linux基础知识

服务器搭建还是需要一些Linux知识的,这节就聊点基础的。 文件权限操作 查看权限 Linux中每个文件对每个用户来说都有对应的权限,在任一路径中输入ll就可以查看这些信息: rootip-*** /usr/local # ll total 32K drwxr-xr-x 2 root root 4.0K J…

seo从入门到精通_从入门到精通,新人必看的3本书SEO书籍

SEO入门书本引荐:从入门到通晓,新人必看的3本书在这个网上学习泛滥的年代,很多人都习气在网络上找教程学习,无论上视频教程,学习论坛,或是网上课堂等等。但也有些人仍是更习气看书学习的,很多人…

linux firefox 脚本,linux下调整firefox的有用设置(高分辨率下需要)

注:自己一般比较喜欢opensuse,所以以下所说皆是在opensuse下的做法,在其他发行版下应该也差不多firefox69 默认禁用了userchrome.css,需要把about:config 中的选项toolkit.legacyUserProfileCustomizations.stylesheets设置为true界面字体大小…

读懂python代码_Python面试|一文让你读懂if __name__==’__main__’的含义

程序入口对于很多编程语言来说,程序都必须要有一个入口,比如 C,C,以及完全面向对象的编程语言 Java,C# 等。如果你接触过这些语言,对于程序入口这个概念应该很好理解,C 和 C 都需要有一个 main …

C语言程序设计第三节课作业

1 指针是一个存储计算机内存地址的变量。从指针指向的内存读取数据称作指针的取值。指针可以指向某些具体类型的变量地址,例如int、long和double。指针也可以是void类型、NULL指针和未初始化指针。根据出现的位置不同,操作符 * 既可以用来声明一个指针变…

linux netcat测试udp端口,使用nc(netcat)测试udp协议与端口连通性

[v1.10]connect to somewhere: netcat [-options] hostname port[s] [ports] …listen for inbound: netcat -l -p port [-options] [hostname] [port]options:-g gateway source-routing hop point[s], up to 8-G num source-routing pointer: 4, 8, 12, …-h this cruft-i se…

Hession矩阵与牛顿迭代法

1、求解方程。 并不是所有的方程都有求根公式,或者求根公式很复杂,导致求解困难。利用牛顿法,可以迭代求解。 原理是利用泰勒公式,在x0处展开,且展开到一阶,即f(x) f(x0)(x-x0)f(x0) 求解方程f…

抽象工厂模式_设计模式——抽象工厂模式

阅读目录使用频率:★★★★★一、什么是抽象工厂模式二、补充说明三、角色四、例子使用频率:★★★★★一、什么是抽象工厂模式就是对一组具有相同主题的工厂进行封装(维基百科解释的很到位);例如:生产一台PC机,使用工…

Linux启动和退出系统的方法,实验二 Linux的启动与关闭

实验二 Linux的启动与关闭一、实验目的(1)掌握linux操作系统正确的启动与关闭方法;(2)理解系统运行级的概念,掌握查看和设置的方法;(3)理解系统运行级服务的概念,掌握查看、开启和关闭的方法;(4)理解LILO和GRUB的原理&…

linux需要什么基础,学linux需要什么基础?

近几年来,随着计算机网络的发展,越来越多的人学习 linux。对于想要从事运维工作或者从事智能开发方面的同学来说,学习 linux 是必要的。linux 的学习并不简单,那么这篇文章 w3cschool 小编来告诉你,学 linux 需要什么基…

python arima模型_Python时间序列处理之ARIMA模型的使用讲解

ARIMA模型ARIMA模型的全称是自回归移动平均模型,是用来预测时间序列的一种常用的统计模型,一般记作ARIMA(p,d,q)。ARIMA的适应情况ARIMA模型相对来说比较简单易用。在应用ARIMA模型时,要保证以下几点:时间序列数据是相对稳定的&am…