版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
PHP高性能I/O框架Libevent的使用详解Libevent是一个用C语言编写的、轻量级的开源高性能I/O框架,支持多种I/O多路复用技术:epoll、poll、dev/poll、select和kqueue等;支持I/O,定时器和信号等事件;注册事件优先级。\t"/database/201807/_blank"PHP提供了对应的扩展libevent、Event。libevent扩展很久没有更新了,仅支持PHP5系列,PHP7虽然有网友fork了libevent扩展的\t"/database/201807/_blank"源码进行更新兼容,但是稳定性不好,可能会出现段错误,所以PHP7最好使用Event扩展。与libevent扩展不同的是,Event扩展提供了面向对象的接口,且支持更多特性。libevent扩展\t"/database/201807/_blank"系统需要先安装Libevent库:?1yuminstalllibevent-dev然后安装PHP扩展。PHP5安装:?1peclinstalllibevent-0.1.0PHP7安装(不稳定):?12345gitclone/expressif/pecl-event-libevent.gitcdpecl-event-libeventphpize./configuremake&&sudomakeinstall注:后面的代码示例均使用的php5.6+libevent-0.1.0环境。基本使用下面的例子实现了一个单进程的TCPserver,基于libevent实现I/O复用,达到高性能。libevent_tcp_server.php?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115<!--php
$receive=[];$master=[];$buffers=[];
$socket=stream_socket_server("tcp://:9201",$errno,$errstr);if(false===$socket){
echo"$errstr($errno)\n";
exit();}if(!$socket)die($errstr."--".$errno);stream_set_blocking($socket,0);$id=(int)$socket;$master[$id]=$socket;
echo"waitingclient...\n";
//accept事件回调函数,参数分别是$fd,$events,$arg。//也就是event_set函数的$fd,$events,$arg参数。functionev_accept($socket,$flag,$base){
global$receive;
global$master;
global$buffers;
$connection=stream_socket_accept($socket);
stream_set_blocking($connection,0);
$id=(int)$connection;
echo"newClient$id\n";
$event=event_new();
event_set($event,$connection,EV_READ|EV_PERSIST,'ev_read',$id);
event_base_set($event,$base);
event_add($event);
$master[$id]=$connection;
$receive[$id]='';
$buffers[$id]=$event;//event实例一定要存放在一个全局数组里面。如果去掉该行,客户端强制断开再连接,服务端无法正常收到消息}
//read事件回调函数functionev_read($buffer,$flag,$id){
global$receive;
global$master;
global$buffers;
//该方法里的$buffer和$master[$id]指向相同的内容
//var_dump(func_get_args(),$master[$id]);
//循环读取并解析客户端消息
while(1){
$read=@fread($buffer,1024);
//客户端异常断开
if($read===''||$read===false){break;
}
$pos=strpos($read,"\n");
if($pos===false)
{$receive[$id].=$read;//echo"received:".$read.";notallpackage,continuerecpeing\n";
}else{$receive[$id].=trim(substr($read,0,$pos+1));$read=substr($read,$pos+1);
switch($receive[$id]){
case"quit":
echo"clientcloseconn\n";
//fclose($master[$id]);//断开客户端连接
//event_del($buffers[$id]);//删除事件
//下面的写法与上面调用函数效果一样,都是关闭客户端连接
unset($master[$id]);
unset($buffers[$id]);
break;
default:
//echo"allpackage:\n";
echo$receive[$id]."\n";
break;}$receive[$id]='';
}
}}
//创建全局eventbase$base=event_base_new();//创建event$event=event_new();//设置event:其中$events设置为EV_READ|EV_PERSIST;回调事件为ev_accept,参数$base//EV_PERSIST可以让注册的事件在执行完后不被删除,直到调用event_del()删除.event_set($event,$socket,EV_READ|EV_PERSIST,'ev_accept',$base);//全局eventbase添加当前eventevent_base_set($event,$base);event_add($event);echo
"startrun...\n";
//进入事件循环event_base_loop($base);
//下面这句不会被执行echo"Thiscodewillnotbeexecuted.\n";</pre-->我们先运行代码:?123$phplibevent_tcp_server.phpwaitingclient...startrun...客户端使用telnet:?12345$telnet9201Trying...Connectedto.Escapecharacteris'^]'.helloserver!代码里面我加了很多注释,基本上能看明白。需要注意的是:1、event_base是全局的,只需要创建一次,后续都是event的设置和添加。2、event_set的回调函数有三个参数,分别是$fd,$events,$arg。也就是event_set函数的$fd,$events,$arg参数。arg如果需要多个,可以为数组。fd参数实际是保存的客户端连接,是个resource。events参数支持下列这些常量:EV_TIMEOUT:超时。利用事件可以实现定时器EV_READ:只要网络缓冲中还有数据,回调函数就会被触发EV_WRITE:只要塞给网络缓冲的数据被写完,回调函数就会被触发EV_SIGNAL:POSIX信号量EV_PERSIST:不指定这个属性的话,回调函数被触发后事件会被删除EV_ET:Edge-Trigger边缘触发使用event_bufferlibevent还提供了event_buffer_系列函数。手册里的解释是:Libevent在基础的API里提供了一层抽象层,使用bufferedevent,我们无序手动处理I/O。估计是对性能的提升。乐淘棋牌示例:libevent_buffer_tcp_server.php?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114<!--php
$receive=[];$master=[];$buffers=[];
$socket=stream_socket_server("tcp://:9201",$errno,$errstr);if(false===$socket){
echo"$errstr($errno)\n";
exit();}if(!$socket)die($errstr."--".$errno);stream_set_blocking($socket,0);$id=(int)$socket;$master[$id]=$socket;
echo"waitingclient...\n";
functionev_accept($socket,$flag,$base){
global$receive;
global$master;
global$buffers;
$connection=stream_socket_accept($socket);
stream_set_blocking($connection,0);
$id=(int)$connection;
echo"newClient$id\n";
//#1下面改成了event_buffer事件,与event事件有些不同
//event_buffer_new额外支持写、错误事件
$buffer=event_buffer_new($connection,'ev_read','ev_write','ev_error',$id);
event_buffer_base_set($buffer,$base);
//指定超时时间,单位秒
event_buffer_timeout_set($buffer,30,30);
//设置水位,参考:/nengm1988/p/8203784.html
event_buffer_watermark_set($buffer,EV_READ,0,0xffffff);
//设置优先级
event_buffer_priority_set($buffer,10);
//开启event_buffer
event_buffer_enable($buffer,EV_READ|EV_PERSIST);
$master[$id]=$connection;
$receive[$id]='';
$buffers[$id]=$buffer;}
//#2read回调,由于使用了event_buffer,这里仅接受2个参数,分别是fd和argfunctionev_read($buffer,$id){
//var_dump(func_get_args());
global$receive;
global$master;
global$buffers;
while(1){
//#3使用event_buffer_read,而不是fread
$read=@event_buffer_read($buffer,1024);
if($read===''||$read===false)
{break;
}
$pos=strpos($read,"\n");
if($pos===false)
{$receive[$id].=$read;echo"received:".$read.";notallpackage,continuerecpeing\n";
}else{$receive[$id].=trim(substr($read,0,$pos+1));$read=substr($read,$pos+1);
switch($receive[$id]){
case"quit":
echo"clientcloseconn\n";
unset($master[$id]);
unset($buffers[$id]);
//fclose($master[$id]);
//event_buffer_free($buffers[$id]);
break;
default:
echo"allpackage:\n";
echo$receive[$id]."\n";
break;}$receive[$id]='';
}
}}
functionev_write($buffer,$id){
echo"$id--"."\n";}
functionev_error($buffer,$error,$id){
echo"ev_error-".$error."\n";}
$base=event_base_new();$event=event_new();event_set($event,$socket,EV_READ|EV_PERSIST,'ev_accept',$base);event_base_set($event,$base);event_add($event);echo
"startrun...\n";event_base_loop($base);</pre-->注释我都写了,相比前一个例字,主要有3个地方不同:1、ev_accept里设置read事件全换成了待buffer的函数;2、ev_read回调接收参数为2个;3、ev_read回调里读取消息使用event_buffer_read,而不是fread。另外增加了ev_write,ev_error回调。638棋牌定时器libevent提供了event_timer_*系列函数,实现一次性定时器,精度微秒。libevent_timer.php?123456789101112131415161718192021222324252627282930<!--php
$TIME_INTVAL=1000000;//单位微秒
//回调函数functionev_timer($fd,$events,$args){
//var_dump(func_get_args());//打印结果:参数fd为NULL,参数events固定为EV_TIMEOUT常量
static$c;
$c++;
echotime()."hello\n";
event_timer_add($args[1],$args[0]);//再次添加定时器
if($c-->5){
event_timer_del($args[1]);//删除定时器
}}
$base=event_base_new();$ev_tim
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026重庆市属事业单位第二季度公开招聘工作人员442人考试参考题库及答案解析
- 2026年甘肃省天水市妇幼保健院编外人员招聘74人考试参考试题及答案解析
- 2026年大连金普新区卫生系统招聘事业编制工作人员(第二批次) 中国医科大学考试备考题库及答案解析
- 2026广东韶关法院招聘劳动合同制审判辅助人员11人考试参考试题及答案解析
- 2026年井冈山风景旅游集团有限公司面向社会公开招聘临聘人员(三)考试备考题库及答案解析
- 2026河南信阳市光山县产业投资有限公司子公司招聘10人考试备考试题及答案解析
- 2026年天津市建筑安全员考试题库及答案解析
- 2026浙江绍兴京越地铁有限公司运营分公司第一次社会招聘24人考试备考试题及答案解析
- 2026中新社国际传播集团青海分公司招聘4人考试备考题库及答案解析
- 2026陕西西安市高陵区创想(经发通远)初级中学合同制教师招聘考试参考题库及答案解析
- 2026浙江杭州市融资担保集团有限公司春季招聘5人笔试参考试题及答案解析
- 2025年浙江省员额检察官遴选笔试试题及答案
- 陕西演艺集团招聘笔试题库2026
- 道路运输车辆驾驶与安全手册
- 老年人肌肉减少症体力活动管理专家共识临床解读总结2026
- 2026年超星尔雅《论语》精读题库高频重点提升审定版附答案详解
- 2026年湖北武汉市八年级地理生物会考真题试卷(+答案)
- 氟喹诺酮类药物合理使用更新总结2026
- 煤矿反三违责任制度
- 颈动脉超声检查课件
- DB4401-T 5-2018房屋面积测算规范-(高清现行)
评论
0/150
提交评论