任何一款拥有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 参阅 Ud 本机格式的双精度浮点数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);
原文链接:
socket 相关方法帮助文档