最近一段時間在看有關Python相關的知識,特別是其中關於網絡通信的內容。在大部分的書本示例中,客戶端和服務器端通信的內容都是文本信息,例如“hello world!”之類的信息。但是在實際應用中,我們看到的大部分數據時二進制數據,如“0x12345678”。所以這時候,就需要使用到Python中的struct來處理一下了。
一、struct簡介
看到struct這么英文單詞,大家應該並不陌生,因為c/c++中就有struct,在那里struct叫做結構體。在Python中也使用struct,這充分說明了這個struct應該和c/c++中的struct有很深的淵源。Python正是使用struct模塊執行Python值和C結構體之間的轉換,從而形成Python字節對象。它使用格式字符串作為底層C結構體的緊湊描述,進而根據這個格式字符串轉換成Python值。
二、主要函數
struct模塊中最主要的三個函數式pack()、unpack()、calcsize()。
pack(fmt, v1, v2, ...) ------ 根據所給的fmt描述的格式將值v1,v2,...轉換為一個字符串。
unpack(fmt, bytes) ------ 根據所給的fmt描述的格式將bytes反向解析出來,返回一個元組。
calcsize(fmt) ------ 根據所給的fmt描述的格式返回該結構的大小。
三、格式字符
格式字符有下面的定義:
Format | C Type | Python | 字節數 |
x | pad byte | no value | 1 |
c | char | bytes of length 1 | 1 |
b | signed char | integer | 1 |
B | unsigned char | integer | 1 |
? | _Bool | bool | 1 |
h | short |
integer | 2 |
H | unsigned short | integer | 2 |
i | int | integer | 4 |
I | unsigned int | integer | 4 |
l | long | integer | 4 |
L | unsigned long | integer | 4 |
q | long long | integer | 8 |
Q | unsigned long long | integer | 8 |
f | float | float | 4 |
d | double | float | 8 |
s | char[] | bytes | 1 |
p | char[] | bytes | 1 |
P | void * | integer |
注意: 1. c,s和p按照bytes對象執行轉碼操作,但是在使用UTF-8編碼時,也支持str對象。
2. ‘?’按照C99中定義的_Bool類型轉碼。如果該類型不可用,可使用一個char冒充。
3. ‘q'和’Q‘僅在64位系統上有用。
四.示例
現在我們有了格式字符串,也知道了封裝函數,那現在先通過一兩個例子看一看。
例一:比如有一個報文頭部在C語言中是這樣定義的
struct header
{
unsigned short usType;
char[4] acTag;
unsigned int uiVersion;
unsigned int uiLength;
};
在C語言對將該結構體封裝到一塊緩存中是很簡單的,可以使用memcpy()實現。在Python中,使用struct就需要這樣:
str = struct.pack('B4sII', 0x04, 'aaaa', 0x01, 0x0e)
'B4sII' ------ 有一個unsigned short、char[4], 2個unsigned int。其中s之前的數字說明了字符串的大小 。
type, tag, version, length = struct.unpack('B4sll', str)
例二:
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
data=struct.pack('IIIIi',dwStrHeader,dwDataLen,dwDevID,dwChnHLSD,nVUValue)
s.sendto(data,('192.168.0.199',33333))
s.close()