pack和unpack在一般的程序中还真的不容易见到,但是如果你用过很久以前的php生成excel你就会知道了。他的excel的头就是pack出来的
最近在尝试与C交互的时候又用上了这玩意,所以不得不再看看。其实就是C要求我一定要有包头。。。其实纯字符串也不错嘛。干嘛非得搞个包头呢?真纠结 .。
手册上有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 要求的多,那么多余的参数被忽略。
下面还是用例子来说明用法会容易理解一点:
PHP代码
- 关于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.csdn.net/jojobb3138688/archive/2007/05/07/1598609.aspx
我上面的内容来自于:http://blog.sina.com.cn/s/blog_3eba8f1c0100nq9r.html,我现在已经顺利的使用完了。黑黑
还有的参考资料:
http://bbs.phpchina.com/thread-104492-1-1.html
http://hi.baidu.com/chinetman/item/f78a71d847e7d638e2108fda
说到获取公网IP,那方法是相当的多啊
1、利用第三方服务:ip138,用脚本访问他的首页,然后正则取出自己的IP
2、还是处用第三方的服务,如QQ,那种QQ判断来源IP,然后得到地址URL,连上去也能获取IP,当然也得正则
3、自己在自己的服务器上架个服务。返回公网IP,
4、利用dns的服务,比如 这样:
XML/HTML代码
- function getClientIp(){
- $socket = socket_create(AF_INET, SOCK_STREAM, 6);
- $ret = socket_connect($socket,'ns1.dnspod.net',6666);
- $buf = socket_read($socket, 16);
- socket_close($socket);
- return $buf;
- }
5、利用tracert,基本上也能获取 IP。ping也行。只是麻烦了一点
6、如果是本机直接拨号,那就方便了ifconfig , ipconfig /all也可以
好吧,我感觉又被xcache骗了。当然也可能是他们没注意吧。
在网站上,他们说:
修复版本. XCache admin 页面有大量改进, 增加 namespace 支持, 等等. 更新 API, 新增了一些 INI 设置. 新增 "诊断" 模块给出一些专家级建议 (htdocs 中). 进程异常时自动禁用缓存 (运行期间). 警告: 本版本开始使用 extension= 来加载 XCache. 不再支持采用 zend_extension= 方式加载.
再接着说上面的那句警告:本版本开始使用Extension那句
OK,当我装完的时候:
XML/HTML代码
- root@MyDebian64Bit:~/xcache-3.0.0# make install
- Installing shared extensions: /usr/lib/php5/20090626/
你看,成功了,但是看了一下xcache.ini。。。
XML/HTML代码
- [xcache-common]
- ;; install as zend extension (recommended), normally "$extension_dir/xcache.so"
- zend_extension = /usr/lib/php5/20090626/xcache.so
一下子就与说明不太一致了
想不到,我的http://xiaocaipu.com还没有上线,我的微信功能却已经正常在运作了。
打开微信搜索好友,如果按帐号添加,就搜索:xiaocaipu,如果搜索公众帐号,就搜:小菜谱。当然,你懒的话,就扫描这个:
小LOGO是http://82982.com的小茗帮忙做的。。那一群设计师的朋友啊什么的,都说自己没空,我纠结啊。
不知道这个帐号是做什么的?那我得上好多图了。。。
先上两个简单的图吧
这些只是基础功能,还有相对比较高级一点的功能:
pcntl在很久很久之前就听过了,但是一直没有尝试着真正要用它。这不,遇到socket问题了,看socket,遇到pcntl了,再看看吧。
这里是某个人的测试代码:
PHP代码
- <?php
-
-
-
-
-
-
-
-
- function new_child($func_name)
- {
- $args = func_get_args();
- unset($args[0]);
- $pid = pcntl_fork();
- if ($pid == 0) {
- function_exists($func_name) and exit(call_user_func_array($func_name, $args)) or exit(-1);
- }
- else if ($pid == -1) {
- echo "Couldn’t create child process .";
- }
- }
-
- function test($prefix, $num)
- {
- while ($i++ < $num) {
- echo $prefix . $i ."\n";
- }
- }
-
- new_child("test", "child process ", 100);
-
- test("parent process", 100);
-
- ?>
因为上面有作者有注释,所以我就不再多贴这篇文章的地址了。原网页的代码是错误的。我改了一下。原作者说的是:父进程输出50个左右时,子进程就开始运行了。我这边不是。我把数据改成1000后,发现父进程在950多的时候,子进程开始运行了。
当然,看手册也可以,对了,风雪之隅也写过类似的文章,http://www.laruence.com/2009/06/11/930.html,他提到的优点就是:
XML/HTML代码
- 优点:
- 1. 使用多进程, 子进程结束以后, 内核会负责回收资源
- 2. 使用多进程,子进程异常退出不会导致整个进程Thread退出. 父进程还有机会重建流程.
- 3. 一个常驻主进程, 只负责任务分发, 逻辑更清楚.
然后他的代码就与上面有点区别,不过说白了还是大同小异:
PHP代码
- #!/bin/env php
- <?php
-
-
-
-
-
-
-
-
-
- if (substr(php_sapi_name(), 0, 3) !== 'cli') {
- die("This Programe can only be run in CLI mode");
- }
-
-
- set_time_limit(0);
-
- $pid = posix_getpid();
- $user = posix_getlogin();
-
- echo <<<EOD
- USAGE: [command | expression]
- input php code to execute by fork a new process
- input quit to exit
-
- Shell Executor version 1.0.0 by laruence
- EOD;
-
- while (true) {
-
- $prompt = "\n{$user}$ ";
- $input = readline($prompt);
-
- readline_add_history($input);
- if ($input == 'quit') {
- break;
- }
- process_execute($input . ';');
- }
-
- exit(0);
-
- function process_execute($input) {
- $pid = pcntl_fork();
- if ($pid == 0) {
- $pid = posix_getpid();
- echo "* Process {$pid} was created, and Executed:\n\n";
- eval($input);
- exit;
- } else {
- $pid = pcntl_wait($status, WUNTRACED);
- if (pcntl_wifexited($status)) {
- echo "\n\n* Sub process: {$pid} exited with {$status}";
- }
- }
- }
做个笔记。