最近看一点python的代码,发现struct这个包在处理网络编程上非常强大,pack和unpack函数能很轻松地将数据组包拆包,如下所示:
#! /usr/bin/env python官方手册有格式参数的说明,摘录如下,其中感叹号表示网络序字节流,H代表无符号短整型,B代表无符号字符,I代表无符号整形。
import socket, struct, time, re
if __name__ == '__main__':
num1 = 5
num2 = 10
str1 = 0x00001000
str2 = 0x00002000
cha1 = 3
cha2 = 65
pack_res = struct.pack('!HHIIBB', num1, num2, str1, str2, cha1, cha2)
print "after pack "
print "pack_res", pack_res
n1,n2,s1,s2,c1,c2 = struct.unpack("!HHIIBB", pack_res)
print "after unpack"
print "n1 = ", n1
print "n2 = ", n2
print "s1 = ", s1
print "s2 = ", s2
print "c1 = ", c1
print "c2 = ", c2
'''
after pack
pack_res
??????????...
after unpack
n1 = 5
n2 = 10
s1 = 4096
s2 = 8192
c1 = 3
c2 = 65
'''
Character | Byte order | Size | Alignment |
---|---|---|---|
@ | native | native | native |
= | native | standard | none |
< | little-endian | standard | none |
> | big-endian | standard | none |
! | network (= big-endian) | standard | none |
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 | ||
p | char[] | string | ||
P | void * | integer | (5), (3) |
python语法支持函数返回多个结果值,而php没有这种性质,所以php的unpack函数使用上稍有区别,比如同样是实现上面的功能,php的写法如下:
<?php可以看到我们unpack的时候,是打包到一个关联数组中,关联数组的内容在format格式化时说明,还有一点需要注意的是,php与python的格式化参数不一致的,需要参照各自的定义。比如python的HIB分别对应php的nNC。php的格式化参数如下:
$num1 = 5;
$num2 = 10;
$str1 = 0x00001000;
$str2 = 0x00002000;
$cha1 = 3;
$cha2 = 65;
$pack_res = pack("nnNNCC",$num1,$num2,$str1,$str2,$cha1,$cha2);
echo "after pack\n";
echo "pack_res=".$pack_res;
$unpack_res = unpack("n2num/N2str/C*cha",$pack_res);
var_dump($unpack_res);
/*
after pack
?????????
pack_res=array(6) {
["num1"]=>
int(5)
["num2"]=>
int(10)
["str1"]=>
int(4096)
["str2"]=>
int(8192)
["cha1"]=>
int(3)
["cha2"]=>
int(65)
}
*/
?>
Code | Description |
---|---|
a | NUL-padded string |
A | SPACE-padded string |
h | Hex string, low nibble first |
H | Hex string, high nibble first |
c | signed char |
C | unsigned char |
s | signed short (always 16 bit, machine byte order) |
S | unsigned short (always 16 bit, machine byte order) |
n | unsigned short (always 16 bit, big endian byte order) |
v | unsigned short (always 16 bit, little endian byte order) |
i | signed integer (machine dependent size and byte order) |
I | unsigned integer (machine dependent size and byte order) |
l | signed long (always 32 bit, machine byte order) |
L | unsigned long (always 32 bit, machine byte order) |
N | unsigned long (always 32 bit, big endian byte order) |
V | unsigned long (always 32 bit, little endian byte order) |
f | float (machine dependent size and representation) |
d | double (machine dependent size and representation) |
x | NUL byte |
X | Back up one byte |
@ | NUL-fill to absolute position |