1. 程式人生 > >Python的功能模塊[1] -> struct -> struct 在網絡編程中的使用

Python的功能模塊[1] -> struct -> struct 在網絡編程中的使用

之間 ppr codes head ieee other typeerror truncate calculate

struct模塊 / struct Module


在網絡編程中,利用 socket 進行通信時,常常會用到 struct 模塊,在網絡通信中,大多數傳遞的數據以二進制流(binary data)存在。傳遞字符串時無需過多擔心,但傳遞 int,char 之類的基本數據時,就需要一種機制將某些特定的結構體類型打包成二進制流的字符串,然後在進行網絡傳輸,而接收端也可以通過某種機制進行解包還原出原始數據。struct 模塊便提供了這種機制,該模塊主要作用就是對 python 基本類型值與用 python 字符串格式表示的 C struc 類型間的轉化(This module performs conversions between Python values and C structs represented as Python strings.)。

另一種使用場景在與 python 與其他語言之間數據交換時使用,例如 C++ 寫的客戶端發送了一個 int 型(4字節)的數據到 Python 的服務器,Python 接收到這個數據時,需要解析成 Python 認識的整數,此時就將用到 struct 模塊。

函數 / Function


pack()函數

函數調用: bs = struct.pack(format, *argv)

函數功能: 用於將數據按照格式打包成 bytes 形式

傳入參數: format, *argv

format: str 類型,為打包的格式

*argv: 需要打包的數據,多種不同數據由 ’,’ 隔開,與 format 對應

返回參數: bs

bs: byte 類型,為打包後的二進制數據

unpack()函數

函數調用: data = struct.unpack(format, bstr)

函數功能: 用於將數據按照格式從 bytes 形式中解碼出來

傳入參數: format, bstr

format: str 類型,為解碼的格式

bstr: byte 類型,需要解碼的數據,多種不同數據由 ’,’ 隔開,與 format 對應

返回參數: data

data: tuple 類型,為解碼獲得的數據組

calcsize()函數

函數調用: len = struct.calcsize(format)

函數功能: 用於計算以 format 格式形成的數據占用的字節數

傳入參數: format

format: str 類型,為打包解包的格式,如 ‘H’,‘h’,‘I’ 等

返回參數: len

len: int 類型,格式化數據占用的字節數

pack_into()函數

函數調用: data = struct.pack_into(format, buffer, offset, *argv)

函數功能: 用於將數據依照 format 進行打包,以 offset 開頭存入 buffer 中

傳入參數: format, buffer, offset, *argv

format: str 類型,為打包解包的格式

buffer: instance 類型,可由 ctypes.create_string_buffer(size) 生成,buf.raw 查看

offset: int 類型,buffer 中的起始位數偏移

*argv: 需要處理的數據

返回參數:

pack_from()函數

函數調用: struct.pack_from(format, buffer, offset=0)

函數功能: 用於將數據以 offset 開頭從 buffer 中取出,依照 format 進行格式化

傳入參數: format

format: str 類型,為打包解包的格式

buffer: instance 類型,可由 ctypes.create_string_buffer(size) 生成,buf.raw 查看

offset: int 類型,buffer 中的起始位數偏移

返回參數: data

data: tuple 類型,解碼出來的數據組

補充內容 / Complement


pack_into() 函數與 pack_from() 函數的使用

使用二進制打包數據的場景大部分都是對性能要求比較高的使用環境。而在上面提到的 pack 方法都是對輸入數據進行操作後重新創建了一個內存空間用於返回,也就是說我們每次pack 都會在內存中分配出相應的內存資源,這有時是一種很大的性能浪費,struct 模塊還提供了 pack_into() 和 unpack_from() 的方法用來解決這樣的問題,也就是對一個已經提前分配好的 buffer 進行字節的填充,而不會每次都產生一個新對象對字節進行存儲。對比使用 pack 方法打包,pack_into 方法一直是在buffer 對象進行操作,沒有產生多余的內存浪費。另外需要註意的一點是,pack_into 和 unpack_from 方法均是對 string buffer 對象進行操作,並提供了 offset 參數,用戶可以通過指定相應的 offset,使相應的處理變得更加靈活。例如,我們可以把多個對象 pack 到一個 buffer 裏面,然後通過指定不同的 offset 進行 unpack。

struct類型參照表

Format

C Type

Python type

Standard size

Notes

x

pad byte

no value

c

char

string of length 1

1

b

signed char

integer

1

(3)

B

unsigned char

integer

1

(3)

?

_Bool

bool

1

(1)

h

short

integer

2

(3)

H

unsigned short

integer

2

(3)

i

int

integer

4

(3)

I

unsigned int

integer

4

(3)

l

long

integer

4

(3)

L

unsigned long

integer

4

(3)

q

long long

integer

8

(2), (3)

Q

Unsigned long long

integer

8

(2), (3)

F

float

float

4

(4)

d

double

float

8

(4)

s

char[]

string

1

p

char[]

string

P

void *

integer

(5), (3)

Notes:

# 以下內容由後文英文說明翻譯而成,有待後續驗證

1. 在 C99 中,’?’ 轉換碼代表 C 語言的 _bool 類型,如果不行,可以嘗試 char 型模式,對應 1 個 byte;

2.6 版本新增

2. ’q’ 和 ’Q’ 轉換碼只有在 C 的平臺編譯器支持 C long long 類型,或 Windows 下才可在本地模式下使用,在標準模式下均可使用,無限制;

2.2 版本新增

3. 當嘗試給 pack 一個 non-integer 非整數的類型到一個 integer 整數類型時,如果非整數類型有 __index__() 方法,則在 pack 之前會調用該方法,若沒有 __index__() 方法,或者調用 __index__() 方法是出現 TypeError,則會嘗試 __init__() 方法。然而,__init()__ 的使用並不被推薦,並且會產生 DeprecationWarning;

2.7 版本修改: 對 non-integer 使用 __index__() 方法為 2.7 版本新增

2.7 版本修改: 在 2.7 版本之前,並非所有的 integer 轉換碼會調用 __init__() 方法進行轉換,且 DeprecationWarning 只會在 float 浮點型轉換時產生

4. 對於 ’f’ 和 ’d’ 轉換碼,不論平臺是什麽,打包時均使用 IEEE754 二進制 32 格式(對於 ’f’ )和二進制 64 格式(對於 ’d’)

5. P 格式僅對本地字節命令可用(默認的類型或帶有 ’@’ 的二進制命令字符)。二進制命令字符 ’=’ 根據主機系統的不同,使用了小端法/大端法排序,struct 不會將其解釋為本地命令,為此 ’P’ 不可用。

以下為原版英文內容

1. The ‘?‘ conversion code corresponds to the _Bool type defined by C99. If this type is not available, it is simulated using a char. In standard mode, it is always represented by one byte.

New in version 2.6.

2. The ‘q‘ and ‘Q‘ conversion codes are available in native mode only if the platform C compiler supports C long long, or, on Windows, __int64. They are always available in standard modes.

New in version 2.2.

3. When attempting to pack a non-integer using any of the integer conversion codes, if the non-integer has a __index__() method then that method is called to convert the argument to an integer before packing. If no __index__() method exists, or the call to __index__() raises TypeError, then the __int__() method is tried. However, the use of __int__() is deprecated, and will raise DeprecationWarning.

Changed in version 2.7: Use of the __index__() method for non-integers is new in 2.7.

Changed in version 2.7: Prior to version 2.7, not all integer conversion codes would use the __int__() method to convert, and DeprecationWarning was raised only for float arguments.

4. For the ‘f‘ and ‘d‘ conversion codes, the packed representation uses the IEEE 754 binary32 (for ‘f‘) or binary64 (for ‘d‘) format, regardless of the floating-point format used by the platform.

5. he ‘P‘ format character is only available for the native byte ordering (selected as the default or with the ‘@‘ byte order character). The byte order character ‘=‘ chooses to use little- or big-endian ordering based on the host system. The struct module does not interpret this as native ordering, so the ‘P‘ format is not available.

A format character may be preceded by an integral repeat count. For example, the format string ‘4h‘ means exactly the same as ‘hhhh‘.

Whitespace characters between formats are ignored; a count and its format must not contain whitespace though.

For the ‘s‘ format character, the count is interpreted as the size of the string, not a repeat count like for the other format characters; for example, ‘10s‘ means a single 10-byte string, while ‘10c‘ means 10 characters. For packing, the string is truncated or padded with null bytes as appropriate to make it fit. For unpacking, the resulting string always has exactly the specified number of bytes. As a special case, ‘0s‘ means a single, empty string (while ‘0c‘ means 0 characters).

The ‘p‘ format character encodes a “Pascal string”, meaning a short variable-length string stored in a fixed number of bytes, given by the count. The first byte stored is the length of the string, or 255, whichever is smaller. The bytes of the string follow. If the string passed in to pack() is too long (longer than the count minus 1), only the leading count-1 bytes of the string are stored. If the string is shorter than count-1, it is padded with null bytes so that exactly count bytes in all are used. Note that for unpack(), the ‘p‘ format character consumes count bytes, but that the string returned can never contain more than 255 characters.

For the ‘P‘ format character, the return value is a Python integer or long integer, depending on the size needed to hold a pointer when it has been cast to an integer type. A NULL pointer will always be returned as the Python integer 0. When packing pointer-sized values, Python integer or long integer objects may be used. For example, the Alpha and Merced processors use 64-bit pointer values, meaning a Python long integer will be used to hold the pointer; other platforms use 32-bit pointers and will use a Python integer.

For the ‘?‘ format character, the return value is either True or False. When packing, the truth value of the argument object is used. Either 0 or 1 in the native or standard bool representation will be packed, and any non-zero value will be True when unpacking.

struct模塊基本函數應用


 1 import struct
 2 from ctypes import create_string_buffer
 3 
 4 a = 20
 5 b = 400
 6 
 7 # python data --> bytes
 8 def pack():
 9     s = struct.pack(ii, a, b)
10     x = struct.pack(!ii, a, b)
11     print(length:, len(s))
12     print(pack without "!", s)
13     print(repr(s))
14     print(pack with "!", x)
15     return s
16 
17 # bytes --> python data
18 def unpack():
19     s = struct.unpack(ii, struct.pack(ii, a, b))
20     x = struct.unpack(!ii, struct.pack(ii, a, b))
21     print(length:, len(s))
22     print(pack without "!", s)
23     print(repr(s))
24     print(pack with "!", x)
25     return s
26 
27 # calculate the size of corrsponding format
28 def cal():
29     print("len: ", struct.calcsize(i))       # len:  4
30     print("len: ", struct.calcsize(ii))      # len:  8  
31     print("len: ", struct.calcsize(f))       # len:  4  
32     print("len: ", struct.calcsize(ff))      # len:  8  
33     print("len: ", struct.calcsize(s))       # len:  1  
34     print("len: ", struct.calcsize(ss))      # len:  2  
35     print("len: ", struct.calcsize(d))       # len:  8  
36     print("len: ", struct.calcsize(dd))      # len:  16
37 
38 def _into():
39     buf = create_string_buffer(12)
40     # ‘\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00‘
41     print(repr(buf.raw))     
42     print(struct.pack_into("iii", buf, 0, 1, 2, -1))
43 
44 def _from():
45     buf = create_string_buffer(12)
46     # ‘\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00‘
47     print(repr(buf.raw))       
48     print(struct.unpack_from("iii", buf, 0)) 
49 
50 pack()
51 unpack()
52 cal()
53 _into()
54 _from()

Note: 當 format 為 ’ii’ 時,需要 2 個參數,當為 ’2i’ 時,只需要 1 個。

參考鏈接


http://blog.csdn.net/ithomer/article/details/5974029

http://www.cnblogs.com/coser/archive/2011/12/17/2291160.html

Python的功能模塊[1] -> struct -> struct 在網絡編程中的使用