Python數(shù)據(jù)通信——Struct模塊

最近在學(xué)習(xí)python網(wǎng)絡(luò)編程這一塊赋咽,在寫簡單的socket通信代碼時旧噪,遇到了struct這個模塊的使用,當(dāng)時不太清楚這到底有和作用脓匿,后來查閱了相關(guān)資料大概了解了淘钟,在這里做一下簡單的總結(jié)。
了解c語言的人陪毡,一定會知道struct結(jié)構(gòu)體在c語言中的作用米母,它定義了一種結(jié)構(gòu)毡琉,里面包含不同類型的數(shù)據(jù)(int,char,bool等等)铁瞒,方便對某一結(jié)構(gòu)對象進(jìn)行處理。而在網(wǎng)絡(luò)通信當(dāng)中桅滋,大多傳遞的數(shù)據(jù)是以二進(jìn)制流(binary data)存在的慧耍。當(dāng)傳遞字符串時,不必?fù)?dān)心太多的問題,而當(dāng)傳遞諸如int芍碧、char之類的基本數(shù)據(jù)的時候煌珊,就需要有一種機(jī)制將某些特定的結(jié)構(gòu)體類型打包成二進(jìn)制流的字符串然后再網(wǎng)絡(luò)傳輸钾麸,而接收端也應(yīng)該可以通過某種機(jī)制進(jìn)行解包還原出原始的結(jié)構(gòu)體數(shù)據(jù)固灵。python中的struct模塊就提供了這樣的機(jī)制,該模塊的主要作用就是對python基本類型值與用python字符串格式表示的C struct類型間的轉(zhuǎn)化(This module performs conversions between Python values and C structs represented as Python strings.)嚎幸。stuct模塊提供了很簡單的幾個函數(shù)践美,下面寫幾個例子。

1找岖、基本的pack和unpack

struct提供用format specifier方式對數(shù)據(jù)進(jìn)行打包和解包(Packing and Unpacking)陨倡。例如:

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 : <type 'tuple'>  Value: (1, 'abc', 2.700000047683716)

代碼中,首先定義了一個元組數(shù)據(jù)许布,包含int兴革、string、float三種數(shù)據(jù)類型蜜唾,然后定義了struct對象杂曲,并制定了format‘I3sf’,I 表示int袁余,3s表示三個字符長度的字符串擎勘,f 表示 float。最后通過struct的pack和unpack進(jìn)行打包和解包颖榜。通過輸出結(jié)果可以發(fā)現(xiàn)棚饵,value被pack之后,轉(zhuǎn)化為了一段二進(jìn)制字節(jié)串掩完,而unpack可以把該字節(jié)串再轉(zhuǎn)換回一個元組噪漾,但是值得注意的是對于float的精度發(fā)生了改變,這是由一些比如操作系統(tǒng)等客觀因素所決定的且蓬。打包之后的數(shù)據(jù)所占用的字節(jié)數(shù)與C語言中的struct十分相似欣硼。定義format可以參照官方api提供的對照表:


2、字節(jié)順序

另一方面恶阴,打包的后的字節(jié)順序默認(rèn)上是由操作系統(tǒng)的決定的诈胜,當(dāng)然struct模塊也提供了自定義字節(jié)順序的功能,可以指定大端存儲冯事、小端存儲等特定的字節(jié)順序耘斩,對于底層通信的字節(jié)順序是十分重要的,不同的字節(jié)順序和存儲方式也會導(dǎo)致字節(jié)大小的不同桅咆。在format字符串前面加上特定的符號即可以表示不同的字節(jié)順序存儲方式括授,例如采用小端存儲 s = struct.Struct(‘<I3sf’)就可以了。官方api library 也提供了相應(yīng)的對照列表:


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

使用二進(jìn)制打包數(shù)據(jù)的場景大部分都是對性能要求比較高的使用環(huán)境薛夜。而在上面提到的pack方法都是對輸入數(shù)據(jù)進(jìn)行操作后重新創(chuàng)建了一個內(nèi)存空間用于返回,也就是說我們每次pack都會在內(nèi)存中分配出相應(yīng)的內(nèi)存資源版述,這有時是一種很大的性能浪費(fèi)梯澜。struct模塊還提供了pack_into() 和 unpack_from()的方法用來解決這樣的問題,也就是對一個已經(jīng)提前分配好的buffer進(jìn)行字節(jié)的填充渴析,而不會每次都產(chǎn)生一個新對象對字節(jié)進(jìn)行存儲晚伙。

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對象進(jìn)行操作俭茧,沒有產(chǎn)生多余的內(nèi)存浪費(fèi)咆疗。另外需要注意的一點(diǎn)是,pack_into和unpack_from方法均是對string buffer對象進(jìn)行操作母债,并提供了offset參數(shù)午磁,用戶可以通過指定相應(yīng)的offset,使相應(yīng)的處理變得更加靈活毡们。例如迅皇,我們可以把多個對象pack到一個buffer里面,然后通過指定不同的offset進(jìn)行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)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衙熔,一起剝皮案震驚了整個濱河市登颓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌红氯,老刑警劉巖挺据,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異脖隶,居然都是意外死亡扁耐,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門产阱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來婉称,“玉大人,你說我怎么就攤上這事构蹬⊥醢担” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵庄敛,是天一觀的道長俗壹。 經(jīng)常有香客問我,道長藻烤,這世上最難降的妖魔是什么绷雏? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任头滔,我火速辦了婚禮,結(jié)果婚禮上涎显,老公的妹妹穿的比我還像新娘坤检。我一直安慰自己,他們只是感情好期吓,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布早歇。 她就那樣靜靜地躺著,像睡著了一般讨勤。 火紅的嫁衣襯著肌膚如雪箭跳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天潭千,我揣著相機(jī)與錄音谱姓,去河邊找鬼。 笑死脊岳,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的垛玻。 我是一名探鬼主播割捅,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼帚桩!你這毒婦竟也來了亿驾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤账嚎,失蹤者是張志新(化名)和其女友劉穎莫瞬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體郭蕉,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疼邀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了召锈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旁振。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖涨岁,靈堂內(nèi)的尸體忽然破棺而出拐袜,到底是詐尸還是另有隱情,我是刑警寧澤梢薪,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布蹬铺,位于F島的核電站,受9級特大地震影響秉撇,放射性物質(zhì)發(fā)生泄漏甜攀。R本人自食惡果不足惜秋泄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赴邻。 院中可真熱鬧印衔,春花似錦、人聲如沸姥敛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彤敛。三九已至与帆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間墨榄,已是汗流浹背玄糟。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留袄秩,地道東北人阵翎。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像之剧,于是被迫代替她去往敵國和親郭卫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容