当前位置: 首页 > 工具软件 > IntRec-Pack > 使用案例 >

Pack和unpack

荀嘉熙
2023-12-01

用了很久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一个空结束的(和空填充的)字节串
@用空字节填充绝对位置

  1. stringpack(string$format[,mixed$args[,mixed$...]])

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

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

关于Pack:

下面的第一部分把数字值包装成字节:

  1. $out=pack("CCCC",65,66,67,68);#$out等于"ABCD"
  2. $out=pack("C4",65,66,67,68);#一样的东西

下面的对Unicode的循环字母做同样的事情:

  1. $foo=pack("U4",0x24b6,0x24b7,0x24b8,0x24b9);

下面的做类似的事情,增加了一些空:

  1. $out=pack("CCxxCC",65,66,67,68);#$out等于"AB/0/0CD"

打包你的短整数并不意味着你就可移植了:

  1. $out=pack("s2",1,2);
  2. #在小头在前的机器上是"/1/0/2/0"
  3. #在大头在前的机器上是"/0/1/0/2"

在二进制和十六进制包装上,count指的是位或者半字节的数量,而不是生成的字节数量:

  1. $out=pack("B32","...");
  2. $out=pack("H8","5065726c");#都生成“Perl”

a域里的长度只应用于一个字串:

  1. $out=pack("a4","abcd","x","y","z");#"abcd"

要绕开这个限制,使用多倍声明:

  1. $out=pack("aaaa","abcd","x","y","z");#"axyz"
  2. $out=pack("a"x4,"abcd","x","y","z");#"axyz"

a格式做空填充:

  1. $out=pack("a14","abcdefg");#"abcdefg/0/0/0/0/0/0"

关于unpack:

  1. arrayunpack(string$format,string$data)
  2.  
  3. $data="010000020007";
  4. unpack("Sint1/Cchar1/Sint2/Cchar2",$data);
  5.  
  6. ##array('int1'=>1,'char1'=>'0','int2'=>2,'char2'=>7);

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

  1. $lastact=pack('SCSa32a32',0x0040,0x00,0x0006,$username,$passwd)
  2. unpack('Sint1/Cchar1/Sint2/Cchar2/',$lastmessage)
 类似资料: