python struct.unpack

最近在學習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(‘<I3sf’)就可以了。官方api library 也提供了相應的對照列表:

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)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內容