[个人原创]在Centos6.0机器上安装PHP的 libevent PECL Package 扩展步骤及实例,以及实现多个USB转串口的读写实践成功 ,可以用select函数。
yum install libevent-dev 安装libevent
yum install libevent
PHP Extention: http://pecl.php.net/package/libevent/0.0.5
再就是:自己编译 http://libevent.org/
缘起:PHP5的先进之处在于,你可以用stream_select()处理几乎所有的stream-例如你可以通过include STDIN用它接收键盘输入并保存进数组,你还可以接收通过proc_open()打开的管道中的数据。
目的:想用这个函数进行对文件句柄进行监控,其并不是想用于网络的socket句柄,为此做了如下试验:
探索:能否用PHP的stream_select的方式对CentOs下的串口进行监控呢?经过一系列的研究,发现是可以进行多串口的监控的。
研究: 发现会报错,stream_select(): cannot represent a stream of type dio as a select()
解决: 最后,见代码吧。代码下载:
如果,你想时间更短一点,E文是这样说的:
If you want to set an absolute maximum execution time for stream_select in a loop, it's important to decrement the max_time value passed to stream_select.修改了一下的情况,好像效果不明显,呵呵:
完善的第三个版本备案下载,这个实现了对多个串口的同时读写。By:jack
其实主要是对这个超时机制的理解。见下面这段代码的超时:
插曲:dio.raw://[device]
for raw streams anddio.serial://[devicefor serials streams. 这两种stream有什么区别啊?用serial不行,而用raw就Ok了。但是会出现上面的报错:stream_select(): cannot represent a stream of type dio as a select()
php有个libevent扩展,我觉得这个扩展应该可以有更广泛的用途,比如:
(1)异步的服务器端开发框架.
(2)类似unix下的tail命令行.
(3)用php和ZeroMQ实现的一个事件驱动服务器端
http://blog.sina.com.cn/s/blog_60b9ee7f0100qdmh.html
搞录:
问题:
有没有办法在php中实现多线程呢?
假设你正在写一个基于多台服务器的php应用,理想的情况时同时向多台服务器发送请求,而不是一台接一台。
可以实现吗?
回答:
当有人想要实现并发功能时,他们通常会想到用fork或者spawn threads,但是当他们发现php不支持多线程的时候,大概会转换思路去用一些不够好的语言,比如perl。
其实的是大多数情况下,你大可不必使用fork或者线程,并且你会得到比用fork或thread更好的性能。
。。。
PHP5的先进之处在于,你可以用stream_select()处理几乎所有的stream-例如你可以通过include STDIN用它接收键盘输入并保存进数组,你还可以接收通过proc_open()打开的管道中的数据。
日常生活中:
如对多个URL进行异步访问,那个curl_multi一族函数的函数是循环,而用这个就是真正调用类似Linux下的select函数:
实践安装步骤如下:
wget http://pecl.php.net/get/libevent-0.0.4.tgz
checking for libevent support... yes, shared
checking for libevent headers in default path... not found
configure: error: Cannot find libevent headers
root@192.168.1.108:~/software/libevent-0.0.4# yum -y install libevent-devel libevent
不安libevent-devel会在具体安php的libevent扩展时出现找不到.h文件,用指定路径也成也就是下面的:
最好还是安上吧,但要是版本低于1.4还是指定的好,可能会出现问题,这样:
在安php的libevent扩展时加上 -with-libevent=/usr/local/webserver/libevent/:
./configure -with-libevent=/usr/local/webserver/libevent/
---
原因是如下的包没有安装
libevent-devel
把此包安装上去就好了
yum -y install libevent-devel
root@116.255.139.240:~/software# rpm -qa|grep libevent
libevent-1.4.13-1
root@116.255.139.240:~/software# rpm -ql libevent-1.4.13-1
/usr/lib/libevent-1.4.so.2
/usr/lib/libevent-1.4.so.2.1.3
/usr/lib/libevent_core-1.4.so.2
/usr/lib/libevent_core-1.4.so.2.1.3
/usr/lib/libevent_extra-1.4.so.2
/usr/lib/libevent_extra-1.4.so.2.1.3
/usr/share/doc/libevent-1.4.13
/usr/share/doc/libevent-1.4.13/README
libevent的官网:http://libevent.org/
wget https://github.com/downloads/libevent/libevent/libevent-2.0.16-stable.tar.gz
yum -y install libevent-devel 主要是防止编译PHP扩展Configure时出现找不到.h文件,有了它就不用指明:-with-libevent=/usr/local/webserver/libevent/
./configure prefix=/usr/local/webserver/libevent/
扩展安装:http://pecl.php.net/package/libevent
wget http://pecl.php.net/get/libevent-0.0.4.tgz
/usr/local/webserver/php/bin/phpize
./configure -with-libevent=/usr/local/webserver/libevent/
自己安或者yum,注意:yum安可能会出现问题:由於 PHP libevent 需要搭配C 的 libevent 1.4 以上版本 , 所以並非每個 Linux 套件都有 , 例如我的 CentOS 的 libevent 版本就比較舊 , 因此要自行編譯 , 以下就說明 CentOS 5.4 下成功編譯 PHP libevent 的步驟,PHP Warning: stream_select(): supplied argument is not a valid stream resource .
root@192.168.1.108:~/software/libevent-0.0.4# ./configure -with-libevent=/usr/local/webserver/libevent/
root@192.168.1.108:~/software/libevent-0.0.4# make;make install
......
........
Build complete.
Don't forget to run 'make test'.
Installing shared extensions: /usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20090626/
安装完毕,如下:
/usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20090626/libevent.so
DownLoad 测试源码,来自网上:
代码示例,来自网上,注释部分代码,测试读部分是ok的,如下:
网上其他的步骤,主要是注意不有yum默认的安装方法【由於 PHP libevent 需要搭配C 的 libevent 1.4 以上版本 , 所以並非每個 Linux 套件都有 , 例如我的 CentOS 的 libevent 版本就比較舊 , 因此要自行編譯 , 以下就說明 CentOS 5.4 下成功編譯 PHP libevent 的步驟】:
1. 編譯 libevent
解開 libevent source code , 進入 source code 目錄
執行 ./configure –prefix=/usr/local
執行 make
執行 make install
2. 編譯 PHP libevent
解開 PHP libevent source code , 進入 source code 目錄
執行 phpize
執行 ./configure –with-libevent=/usr/local
執行 make
執行 make install
這樣會把 libevent.so 安裝到 /usr/lib/php/modoules 或 /usr/lib64/php/modules , 看 os 是 32bit 或 64bit
同时呢,也可以参考下这个URL:http://www.ooso.net/archives/607
附录,关于curl_multi一族函数的问题:
相信许多人对php手册中语焉不详的curl_multi一族的函数头疼不已,它们文档少,给的例子 更是简单的让你无从借鉴,我也曾经找了许多网页,都没见一个完整的应用例子。
curl_multi_add_handle
curl_multi_close
curl_multi_exec
curl_multi_getcontent
curl_multi_info_read
curl_multi_init
curl_multi_remove_handle
curl_multi_select
一般来说,想到要用这些函数时,目的显然应该是要同时请求多个url,而不是一个一个依次请求,否则不如自己循环去调curl_exec好了。
步骤总结如下:
第一步:调用curl_multi_init
第二步:循环调用curl_multi_add_handle
这一步需要注意的是,curl_multi_add_handle的第二个参数是由curl_init而来的子handle。
第三步:持续调用curl_multi_exec
第四步:根据需要循环调用curl_multi_getcontent获取结果
第五步:调用curl_multi_remove_handle,并为每个字handle调用curl_close
第六步:调用curl_multi_close
这里有一个网上找的简单例子,其作者称为dirty的例子,(稍后我会说明为何dirty):
整个使用过程差不多就是这样,但是,这个简单代码有个致命弱点,就是在do循环的那段,在整个url请求期间是个死循环,它会轻易导致CPU占用100%。
现在我们来改进它,这里要用到一个几乎没有任何文档的函数curl_multi_select了,虽然C的curl库对select有说明,但是,php里的接口和用法确与C中有不同。
把上面do的那段改成下面这样:
因为?$active要等全部url数据接受完毕才变成false,所以这里用到了
curl_multi_exec的返回值判断是否还有数据,当有数据的时候就不停调用curl_multi_exec,暂时没有数据就进入select阶段,新数据一来就可以被唤醒继续执行。这里的好处就是CPU的无谓消耗没有了。
另外:还有一些细节的地方可能有时候要遇到:
控制每一个请求的超时时间,在curl_multi_add_handle之前通过curl_setopt去做:
判断是否超时了或者其他错误,在curl_multi_getcontent之前用:curl_error(?$conn[?$i]);
相关参考:
http://www.iteye.com/news/21255-swoole-php-framework
http://code.google.com/p/swoole/
http://blog.163.com/huv520@126/blog/static/2776523920119149283594/
http://matyhtf.iteye.com/blog/844311
实践代码如下,运行成功:
执行如下:
root@116.255.139.240:/home/admin/php/stream_select# php stream_select.php
Program starts at 02:30:27.
Finished with delay of 1.
Finished with delay of 3.
这里的关键在于 PHP 启动了两个独立子进程,取回待完成的第一个进程的输出,然后取回第二个进程的输出,即使后者启动得较早。如果主机是多处理器计算机,并且操作系统已正确配置,则操作系统本身负责将各个子程序分配给不同的处理器。这是在多处理器主机中良好应用 PHP 的一种方法。
时间如下,特别注意是这样的如果是PHp串口实现fd的话,因为只有这个常规的fd才能用stream_select监控,而PHP的串口扩展是不行的,我实践了好几次才发现这个问题,
dio.raw://[device]
for raw streams and
dio.serial://[device
for serials streams.
这两种stream有什么区别啊?这点我不太明白,反正用raw就能读取到,而用serial就不行,
用serial不行,而用raw就Ok了,也就满足了偶的需求,呵呵。
参考的扩展和实践Ok的代码都来自:http://www.cyberspice.org.uk/blog/2010/02/15/serial-io-in-php-using-the-dio-extension/
Ok的读取代码如下:
<?php
Error_reporting(E_ALL);
// Create a stream context that configures the serial port
// And enables canonical input.
$c = stream_context_create(array('dio' =>
array('data_rate' => 9600,
'data_bits' => 8,
'stop_bits' => 1,
'parity' => 0,
'is_canonical' => 1)));
// Are we POSIX or Windows? POSIX platforms do not have a
// Standard port naming scheme so it could be /dev/ttyUSB0
// or some long /dev/tty.serial_port_name_thingy on OSX.
$filename = "dio.raw:///dev/ttyUSB0";
// Open the stream for read only and use it.
$f = fopen($filename, "r+", false, $c);
stream_set_blocking($f, 0);
if ($f) {
echo "Reading from port...\n";
while(1)
{
//$data = fgets($f);
$data = fread($f,10);
if ($data)
{
echo $data."\n";
}
}
}
?>
参考其他网上的实例代码如下,代码来自,http://plugins.svn.wordpress.org/wp-tsina/trunk/wp-tsina.curl.cls.php:
因blog搬家,最后的代码作为附件没有存下来,于是在此补充上:
单个程序读取Ok在raspberry硬件上:
测试结果:
root@raspberrypi:~/phpComSelect# php fopenFromRaspberry.php
SERIAL RX:TTest UART : Uart will ouput the ASCII 123456 if it is right!
SERIAL RX:123456
PHP的select性能测试:
http://blog.163.com/james_huangjian/blog/static/17804934520123126264385/
上文的下载的:simplehttpd.tar.gz 在台湾没有下载到,没有想到在Gaston兄弟的网上找到了,神奇了,如下:
http://gastonwu.com/tmp/simplehttpd.tar.gz
2013年再次做多串口的select实现如下,该功能在raspberry pi里调试通过:
yum install libevent
PHP Extention: http://pecl.php.net/package/libevent/0.0.5
再就是:自己编译 http://libevent.org/
缘起:PHP5的先进之处在于,你可以用stream_select()处理几乎所有的stream-例如你可以通过include STDIN用它接收键盘输入并保存进数组,你还可以接收通过proc_open()打开的管道中的数据。
目的:想用这个函数进行对文件句柄进行监控,其并不是想用于网络的socket句柄,为此做了如下试验:
探索:能否用PHP的stream_select的方式对CentOs下的串口进行监控呢?经过一系列的研究,发现是可以进行多串口的监控的。
研究: 发现会报错,stream_select(): cannot represent a stream of type dio as a select()
解决: 最后,见代码吧。代码下载:
下载文件
如果,你想时间更短一点,E文是这样说的:
If you want to set an absolute maximum execution time for stream_select in a loop, it's important to decrement the max_time value passed to stream_select.修改了一下的情况,好像效果不明显,呵呵:
下载文件
完善的第三个版本备案下载,这个实现了对多个串口的同时读写。By:jack
下载文件
插曲:dio.raw://[device]
for raw streams anddio.serial://[devicefor serials streams. 这两种stream有什么区别啊?用serial不行,而用raw就Ok了。但是会出现上面的报错:stream_select(): cannot represent a stream of type dio as a select()
php有个libevent扩展,我觉得这个扩展应该可以有更广泛的用途,比如:
(1)异步的服务器端开发框架.
(2)类似unix下的tail命令行.
(3)用php和ZeroMQ实现的一个事件驱动服务器端
http://blog.sina.com.cn/s/blog_60b9ee7f0100qdmh.html
搞录:
问题:
有没有办法在php中实现多线程呢?
假设你正在写一个基于多台服务器的php应用,理想的情况时同时向多台服务器发送请求,而不是一台接一台。
可以实现吗?
回答:
当有人想要实现并发功能时,他们通常会想到用fork或者spawn threads,但是当他们发现php不支持多线程的时候,大概会转换思路去用一些不够好的语言,比如perl。
其实的是大多数情况下,你大可不必使用fork或者线程,并且你会得到比用fork或thread更好的性能。
。。。
PHP5的先进之处在于,你可以用stream_select()处理几乎所有的stream-例如你可以通过include STDIN用它接收键盘输入并保存进数组,你还可以接收通过proc_open()打开的管道中的数据。
日常生活中:
如对多个URL进行异步访问,那个curl_multi一族函数的函数是循环,而用这个就是真正调用类似Linux下的select函数:
实践安装步骤如下:
wget http://pecl.php.net/get/libevent-0.0.4.tgz
checking for libevent support... yes, shared
checking for libevent headers in default path... not found
configure: error: Cannot find libevent headers
root@192.168.1.108:~/software/libevent-0.0.4# yum -y install libevent-devel libevent
不安libevent-devel会在具体安php的libevent扩展时出现找不到.h文件,用指定路径也成也就是下面的:
最好还是安上吧,但要是版本低于1.4还是指定的好,可能会出现问题,这样:
在安php的libevent扩展时加上 -with-libevent=/usr/local/webserver/libevent/:
./configure -with-libevent=/usr/local/webserver/libevent/
---
原因是如下的包没有安装
libevent-devel
把此包安装上去就好了
yum -y install libevent-devel
root@116.255.139.240:~/software# rpm -qa|grep libevent
libevent-1.4.13-1
root@116.255.139.240:~/software# rpm -ql libevent-1.4.13-1
/usr/lib/libevent-1.4.so.2
/usr/lib/libevent-1.4.so.2.1.3
/usr/lib/libevent_core-1.4.so.2
/usr/lib/libevent_core-1.4.so.2.1.3
/usr/lib/libevent_extra-1.4.so.2
/usr/lib/libevent_extra-1.4.so.2.1.3
/usr/share/doc/libevent-1.4.13
/usr/share/doc/libevent-1.4.13/README
libevent的官网:http://libevent.org/
wget https://github.com/downloads/libevent/libevent/libevent-2.0.16-stable.tar.gz
yum -y install libevent-devel 主要是防止编译PHP扩展Configure时出现找不到.h文件,有了它就不用指明:-with-libevent=/usr/local/webserver/libevent/
./configure prefix=/usr/local/webserver/libevent/
扩展安装:http://pecl.php.net/package/libevent
wget http://pecl.php.net/get/libevent-0.0.4.tgz
/usr/local/webserver/php/bin/phpize
./configure -with-libevent=/usr/local/webserver/libevent/
自己安或者yum,注意:yum安可能会出现问题:由於 PHP libevent 需要搭配C 的 libevent 1.4 以上版本 , 所以並非每個 Linux 套件都有 , 例如我的 CentOS 的 libevent 版本就比較舊 , 因此要自行編譯 , 以下就說明 CentOS 5.4 下成功編譯 PHP libevent 的步驟,PHP Warning: stream_select(): supplied argument is not a valid stream resource .
root@192.168.1.108:~/software/libevent-0.0.4# ./configure -with-libevent=/usr/local/webserver/libevent/
root@192.168.1.108:~/software/libevent-0.0.4# make;make install
......
........
Build complete.
Don't forget to run 'make test'.
Installing shared extensions: /usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20090626/
安装完毕,如下:
/usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20090626/libevent.so
DownLoad 测试源码,来自网上:
下载文件
代码示例,来自网上,注释部分代码,测试读部分是ok的,如下:
网上其他的步骤,主要是注意不有yum默认的安装方法【由於 PHP libevent 需要搭配C 的 libevent 1.4 以上版本 , 所以並非每個 Linux 套件都有 , 例如我的 CentOS 的 libevent 版本就比較舊 , 因此要自行編譯 , 以下就說明 CentOS 5.4 下成功編譯 PHP libevent 的步驟】:
1. 編譯 libevent
解開 libevent source code , 進入 source code 目錄
執行 ./configure –prefix=/usr/local
執行 make
執行 make install
2. 編譯 PHP libevent
解開 PHP libevent source code , 進入 source code 目錄
執行 phpize
執行 ./configure –with-libevent=/usr/local
執行 make
執行 make install
這樣會把 libevent.so 安裝到 /usr/lib/php/modoules 或 /usr/lib64/php/modules , 看 os 是 32bit 或 64bit
同时呢,也可以参考下这个URL:http://www.ooso.net/archives/607
附录,关于curl_multi一族函数的问题:
相信许多人对php手册中语焉不详的curl_multi一族的函数头疼不已,它们文档少,给的例子 更是简单的让你无从借鉴,我也曾经找了许多网页,都没见一个完整的应用例子。
curl_multi_add_handle
curl_multi_close
curl_multi_exec
curl_multi_getcontent
curl_multi_info_read
curl_multi_init
curl_multi_remove_handle
curl_multi_select
一般来说,想到要用这些函数时,目的显然应该是要同时请求多个url,而不是一个一个依次请求,否则不如自己循环去调curl_exec好了。
步骤总结如下:
第一步:调用curl_multi_init
第二步:循环调用curl_multi_add_handle
这一步需要注意的是,curl_multi_add_handle的第二个参数是由curl_init而来的子handle。
第三步:持续调用curl_multi_exec
第四步:根据需要循环调用curl_multi_getcontent获取结果
第五步:调用curl_multi_remove_handle,并为每个字handle调用curl_close
第六步:调用curl_multi_close
这里有一个网上找的简单例子,其作者称为dirty的例子,(稍后我会说明为何dirty):
整个使用过程差不多就是这样,但是,这个简单代码有个致命弱点,就是在do循环的那段,在整个url请求期间是个死循环,它会轻易导致CPU占用100%。
现在我们来改进它,这里要用到一个几乎没有任何文档的函数curl_multi_select了,虽然C的curl库对select有说明,但是,php里的接口和用法确与C中有不同。
把上面do的那段改成下面这样:
因为?$active要等全部url数据接受完毕才变成false,所以这里用到了
curl_multi_exec的返回值判断是否还有数据,当有数据的时候就不停调用curl_multi_exec,暂时没有数据就进入select阶段,新数据一来就可以被唤醒继续执行。这里的好处就是CPU的无谓消耗没有了。
另外:还有一些细节的地方可能有时候要遇到:
控制每一个请求的超时时间,在curl_multi_add_handle之前通过curl_setopt去做:
判断是否超时了或者其他错误,在curl_multi_getcontent之前用:curl_error(?$conn[?$i]);
相关参考:
http://www.iteye.com/news/21255-swoole-php-framework
http://code.google.com/p/swoole/
http://blog.163.com/huv520@126/blog/static/2776523920119149283594/
http://matyhtf.iteye.com/blog/844311
实践代码如下,运行成功:
执行如下:
root@116.255.139.240:/home/admin/php/stream_select# php stream_select.php
Program starts at 02:30:27.
Finished with delay of 1.
Finished with delay of 3.
这里的关键在于 PHP 启动了两个独立子进程,取回待完成的第一个进程的输出,然后取回第二个进程的输出,即使后者启动得较早。如果主机是多处理器计算机,并且操作系统已正确配置,则操作系统本身负责将各个子程序分配给不同的处理器。这是在多处理器主机中良好应用 PHP 的一种方法。
时间如下,特别注意是这样的如果是PHp串口实现fd的话,因为只有这个常规的fd才能用stream_select监控,而PHP的串口扩展是不行的,我实践了好几次才发现这个问题,
dio.raw://[device]
for raw streams and
dio.serial://[device
for serials streams.
这两种stream有什么区别啊?这点我不太明白,反正用raw就能读取到,而用serial就不行,
用serial不行,而用raw就Ok了,也就满足了偶的需求,呵呵。
参考的扩展和实践Ok的代码都来自:http://www.cyberspice.org.uk/blog/2010/02/15/serial-io-in-php-using-the-dio-extension/
Ok的读取代码如下:
<?php
Error_reporting(E_ALL);
// Create a stream context that configures the serial port
// And enables canonical input.
$c = stream_context_create(array('dio' =>
array('data_rate' => 9600,
'data_bits' => 8,
'stop_bits' => 1,
'parity' => 0,
'is_canonical' => 1)));
// Are we POSIX or Windows? POSIX platforms do not have a
// Standard port naming scheme so it could be /dev/ttyUSB0
// or some long /dev/tty.serial_port_name_thingy on OSX.
$filename = "dio.raw:///dev/ttyUSB0";
// Open the stream for read only and use it.
$f = fopen($filename, "r+", false, $c);
stream_set_blocking($f, 0);
if ($f) {
echo "Reading from port...\n";
while(1)
{
//$data = fgets($f);
$data = fread($f,10);
if ($data)
{
echo $data."\n";
}
}
}
?>
参考其他网上的实例代码如下,代码来自,http://plugins.svn.wordpress.org/wp-tsina/trunk/wp-tsina.curl.cls.php:
因blog搬家,最后的代码作为附件没有存下来,于是在此补充上:
单个程序读取Ok在raspberry硬件上:
测试结果:
root@raspberrypi:~/phpComSelect# php fopenFromRaspberry.php
SERIAL RX:TTest UART : Uart will ouput the ASCII 123456 if it is right!
SERIAL RX:123456
PHP的select性能测试:
http://blog.163.com/james_huangjian/blog/static/17804934520123126264385/
上文的下载的:simplehttpd.tar.gz 在台湾没有下载到,没有想到在Gaston兄弟的网上找到了,神奇了,如下:
http://gastonwu.com/tmp/simplehttpd.tar.gz
2013年再次做多串口的select实现如下,该功能在raspberry pi里调试通过:
作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:http://jackxiang.com/post/4803/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!
最后编辑: jackxiang 编辑于2013-2-23 22:28
评论列表
2011-11-20 14:23 | bokig194
好美.谢谢!祝你快乐
2011-11-20 14:17 | bokig793
丢人了~~~
分页: 1/1 1