pack 和 unpack 的使用

  任何一款拥有socket操作能力的语言都有一个专门用于组包的函数,php也不例外!           

      用了很久php了却很少有机会用php进行一些二进制操作。 最近用php写一个socket客户端连接一个用C++语言开发的游戏服务端。 服务器端开发人员使用了二进制的形式来定义协议的格式。协议格式如下:

   包头(2bytes)+加密(1byte)+命令码(2bytes)+帧内容

1.包头的内容是记录帧内容的长度;
2. 加密:0表示不加密,1表示加密;
3. 命令码为服务端命令识别符号;

    一开始不了解php原来有pack可以来组装二进制包, 走了弯路,让服务端开发人员用C语言帮忙开发了的几个内存操作函数,按照协议规则返回二进制包,然后我将这几个方法编译成一组扩展函数供php使用。
    
    话归正题,本文是介绍如何使用pack和unpack这两个方法的。php官方手册举例太少,不能很容易理解,特别是那些格式化参数的使用。

转摘的参数中文说明:

pack/unpack 的摸板字符字符 含义
a 一个填充空的字节串
A 一个填充空格的字节串
b 一个位串,在每个字节里位的顺序都是升序
B 一个位串,在每个字节里位的顺序都是降序
c 一个有符号 char(8位整数)值
C 一个无符号 char(8位整数)值;关于 Unicode 参阅 U
d 本机格式的双精度浮点数
f 本机格式的单精度浮点数
h 一个十六进制串,低四位在前
H 一个十六进制串,高四位在前
i 一个有符号整数值,本机格式
I 一个无符号整数值,本机格式
l 一个有符号长整形,总是 32 位
L 一个无符号长整形,总是 32 位
n 一个 16位短整形,“网络”字节序(大头在前)
N 一个 32 位短整形,“网络”字节序(大头在前)
p 一个指向空结尾的字串的指针
P 一个指向定长字串的指针
q 一个有符号四倍(64位整数)值
Q 一个无符号四倍(64位整数)值
s 一个有符号短整数值,总是 16 位
S 一个无符号短整数值,总是 16 位,字节序跟机器芯片有关
u 一个无编码的字串
U 一个 Unicode 字符数字
v 一个“VAX”字节序(小头在前)的 16 位短整数
V 一个“VAX”字节序(小头在前)的 32 位短整数
w 一个 BER 压缩的整数
x 一个空字节(向前忽略一个字节)
X 备份一个字节
Z 一个空结束的(和空填充的)字节串
@ 用空字节填充绝对位置


string pack ( string $format [, mixed $args [, mixed $...]] )

一些规则:
1.每个字母后面都可以跟着一个数字,表示 count(计数),如果 count 是一个 * 表示剩下的所有东西。
2.如果你提供的参数比 $format 要求的少,pack 假设缺的都是空值。如果你提供的参数比 $format 要求的多,那么多余的参数被忽略。

下面还是用例子来说明用法会容易理解一点:

关于Pack:

下面的第一部分把数字值包装成字节:
$out = pack("CCCC", 65, 66, 67, 68);      # $out 等于"ABCD"
$out = pack("C4", 65, 66, 67, 68);         # 一样的东西

下面的对 Unicode 的循环字母做同样的事情:
  $foo = pack("U4", 0x24b6, 0x24b7, 0x24b8, 0x24b9);

下面的做类似的事情,增加了一些空:
  $out = pack("CCxxCC", 65, 66, 67, 68);      # $out 等于 "AB/0/0CD"

打包你的短整数并不意味着你就可移植了:
  $out = pack("s2", 1, 2);         
# 在小头在前的机器上是 "/1/0/2/0"
# 在大头在前的机器上是 "/0/1/0/2"

在二进制和十六进制包装上,count 指的是位或者半字节的数量,而不是生成的字节数量:
  $out = pack("B32", "...");
    $out = pack("H8", "5065726c");         # 都生成“Perl”

a 域里的长度只应用于一个字串:
  $out = pack("a4", "abcd", "x", "y", "z");      # "abcd"

要绕开这个限制,使用多倍声明:
  $out = pack("aaaa",    "abcd", "x", "y", "z");   # "axyz"
   $out = pack("a" x 4,   "abcd", "x", "y", "z");   # "axyz"

a 格式做空填充:
  $out = pack("a14", "abcdefg");         # " abcdefg/0/0/0/0/0/0"


关于unpack:

array unpack ( string $format, string $data )

$data = "010000020007";
unpack("Sint1/Cchar1/Sint2/Cchar2",$data);

## array('int1'=>1, 'char1'=>'0','int2'=>2,'char2'=>7);

      最后本文开头讲到的协议使用pack/unpack 举例程序代码为 :


$lastact   = pack('SCSa32a32',0x0040, 0x00, 0x0006, $username, $passwd );

unpack('Sint1/Cchar1/Sint2/Cchar2/',$lastmessage);

;


学习资料:
http://blog.youkuaiyun.com/jojobb3138688/archive/2007/05/07/1598609.aspx

### 关于 `pack` `unpack` 的用法及区别 在 Python 中,`struct.pack()` 函数用于将 Python 值按照给定的格式符转换为字节流表示形式[^1]。而 `struct.unpack()` 则执行相反的操作——它接收一个格式字符串一个包含打包数据的字节串,并将其解析回原始的数据项列表或元组[^2]。 #### 使用示例 下面通过具体的例子来展示如何使用这两个方法: ```python import struct # 打包两个整数到二进制字符串中 binary_data = struct.pack("ii", 20, 400) print(f"Packed Data: {binary_data}") # 解析上述创建的二进制字符串回到原来的数值 original_values = struct.unpack("ii", binary_data) print(f"Unpacked Values: a1={original_values[0]}, a2={original_values[1]}") ``` 这段代码首先利用 `"ii"` 这样的格式化字符串指定了要打包的是两个有符号整数 (`i`) ,接着调用了 `struct.pack()` 方法完成实际的打包操作;之后再用相同的格式化字符串配合 `struct.unpack()` 来恢复原来的数据。 #### 大端模式下的应用实例 当涉及到网络协议或其他特定平台上的数据交换时,可能还需要考虑字节序问题。这里给出一个采用大端模式的例子: ```python from struct import * data = pack(">bhl", 1, 2, 3) # 使用大端方式打包 byte (char), short int, long int unpacked_data = unpack('>bhl', data) # 同样以大端方式进行解码 size_of_struct = calcsize('>bhl') print(f"Data Size: {size_of_struct} bytes") print(f"Unpacked Data: char={unpacked_data[0]}, short_int={unpacked_data[1]}, long_int={unpacked_data[2]}") ``` 此片段展示了怎样指定不同的基本类型并设置它们之间的排列顺序(即字节序),从而确保跨平台兼容性[^3]。 #### 单一值处理案例 对于单个值也可以同样适用这些功能,如下所示: ```python single_value_packed = struct.pack('>H', 56) # 将无符号短整形(ushort)按大端存储 recovered_single_value = struct.unpack('>H', single_value_packed)[0] print(f"Recovered Single Value: {recovered_single_value}") ``` 在这个简单的情况下,仅有一个无符号短整型被压缩成二进制格式后再还原出来[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值