资讯专栏INFORMATION COLUMN

PHP socket初探 --- 硬着头皮继续libevent(二)

jokester / 2495人阅读

摘要:类就是产生各种不同类型事件的产出器,比如定时器事件读写事件等等,为了提升民族荣誉感,我们将这些各种事件比作各种战斗机比如歼歼和歼。类就相对容易介入了,这玩意显然就是一个航空母舰了,为了提升民族荣誉感,我们就把类当作是辽宁舰。

[原文地址:https://blog.ti-node.com/blog...]

实际上php.net上是有event扩展的使用说明手册,但是呢,对于初学者来说却并没有什么卵用,因为没有太多的强有力使用案例代码,也没有给力的User Contributed Notes,所以可能造成的结果就是:根本就看不懂。

这就是event文档,点击这里,你们可以感受一下。从文档上看,event扩展一共实现了如下图几个基础类,其中最常用重要的就是Event和EventBase以及EventConfig三个类了,所以,先围绕这三位开展一下工作。

考虑到你们、我、还有正在看这个文章的其他未知物种,大多数可能并不是搞C语言的老兵油子,所以我得用一些可能并不恰当的案例和比喻来尝试引入这些概念。

libevent中有五个字母是event,实际上就是说“event才是王道”。

Event类就是产生各种不同类型事件的产出器,比如定时器事件、读写事件等等,为了提升民族荣誉感,我们将这些各种事件比作各种战斗机:比如歼10、歼15和歼20。

EventBase类就相对容易介入了,这玩意显然就是一个航空母舰了,为了提升民族荣誉感,我们就把EventBase类当作是辽宁舰。各种Event都必须依靠EventBase才能混口饭吃,这和战斗机有辽宁舰才有底气飞的更高更远是一个道理。一定是先有航母(EventBase),其次是战斗机(Event)挂在航母(EventBase)上。

EventConfig则是一个配置类,实例化后的对象作为参数可以传递给EventBase类,这样在初始化EventBase类的时候会根据这个配置初始化出不同的EventBase实例。类比的话,这个类则有点儿类似于辽宁舰的舰岛,可以配置指挥整个辽宁舰。航空母舰的发展趋势是不需要舰岛的,同样,在实例化EventBase类时候同样也可以不传入EventConfig对象,直接进行实例化也是没有问题的。

下面我们从开始写一个php定时器来步入到代码的节奏中。定时器是大家常用的一个工具,一般phper一说定时器,脑海中第一个想起的绝逼是Linux中的crontab。难道phper们离开了crontab真的就没法混了吗?是的,真的好羞耻,现实告诉我们就是这样的,他们离开了crontab真的就没法混了。那么,是时候通过纯php来搞一波儿定时器实现了!

注意是真的纯php,连Event扩展都不用的那种。


代码保存成timer.php,然后php timer.php运行下,如果不出问题应该能跑起来。但是吧,这个代码有一坨问题。

首先是性能一般( 但是,比使用declare(ticks=1)还是要好不少的 )

其次是代码量确实短小,短小的都让人怀疑:这特么玩意能用?

最后是即便我硬着头皮用,但这玩意只能精确到秒级,逗我?

所以,为了解决以上问题,是时候操作一波儿Event扩展了!

add( $tick );
// eventBase进入loop状态(辽宁舰!走你!)
$eventBase->loop();

将代码保存为tick.php,然后php tick.php执行一下,如下图所示:

这种定时器是持久的定时器(每隔X时间一定会执行一次),如果想要一次性的定时器(隔X时间后就会执行一次,执行过后再也不执行了),那么将上述代码中的“Event::TIMEOUT | Event::PERSIST”修改为“Event::TIMEOUT”即可。

如果你有一些自定义用户数据传递给回调函数,可以利用new Event()的第五个参数,这五个参数可以给回调函数用,如下所示:

 "woshishui",
) );

需要重点说明的是new Event()这行代码了,我把原型贴过来给大家看下:

public Event::__construct ( EventBase $base , mixed $fd , int $what , callable $cb [, mixed $arg = NULL ] )

第一个参数是一个eventBase对象即可

第二个参数是文件描述符,可以是一个监听socket、一个连接socket、一个fopen打开的文件或者stream流等。如果是时钟时间,则传入-1。如果是其他信号事件,用相应的信号常量即可,比如SIGHUP、SIGTERM等等

第三个参数表示事件类型,依次是Event::READ、Event::WRITE、Event::SIGNAL、Event::TIMEOUT。其中,加上Event::PERSIST则表示是持久发生,而不是只发生一次就再也没反应了。比如Event::READ | Event::PERSIST就表示某个文件描述第一次可读的时候发生一次,后面如果又可读就绪了那么还会继续发生一次。

第四个参数就熟悉的很了,就是事件回调了,意思就是当某个事件发生后那么应该具体做什么相应

第五个参数是自定义数据,这个数据会传递给第四个参数的回调函数,回调函数中可以用这个数据。

通过以上的案例代码可以总结一下日常流程:

创建EventConfig(非必需)

创建EventBase

创建Event

将Event挂起,也就是执行了Event对象的add方法,不执行add方法那么这个event对象就无法挂起,也就不会执行

将EventBase执行进入循环中,也就是loop方法

捋清楚了定时器代码,我们尝试来解决一个信号的问题。比如我们的进程是常驻内存的daemon,再接收到某个信号后就会作出相应的动作,比如收到term信号后进程就会退出、收到usr1信号就会执行reload等等。

add();
// 进入循环
echo "进入循环".PHP_EOL;
$eventBase->loop();

将代码保存成tick.php,然后执行php tick.php,代码已经进入循环了,然后我们打开另外一个终端,输入ps aux|grep tick查看一个php进程的pid进程号,对这个进程发送term信号,如下图所示:


奇怪啊,从第一张图看到确实收到term信号了,但是很奇怪为什么这个php进程退出了呢?是因为没有添加Event::PERSIST,修改如下代码如下:


有些心眼多鸡贼的,IO多路复用的方法一共有三个select、poll和epoll(Mac下叫做kqueue),那么我们当前的event扩展用的是哪个方法呢?那么,再表演一波儿:

getMethod().PHP_EOL;
// 跑了许久龙套的config这次也得真的露露手脚了
$eventConfig = new EventConfig;
// 避免使用方法kqueue
$eventConfig->avoidMethod("kqueue");
// 利用config初始化event base
$eventBase = new EventBase( $eventConfig );
echo "当前event的方法是:".$eventBase->getMethod().PHP_EOL;

将代码保存了,然后执行一下,可以看到结果如下图所示:

那么,还有一些更鸡贼的人继续发问,前面提到的边缘触发和水平触发,如何确认呢?既然都用上epoll或者kqueue了,就一定要用边缘触发。

getFeatures();
// 看不到这个判断条件的,请反思自己“位运算”相关欠缺
if( $features & EventConfig::FEATURE_ET ){
  echo "边缘触发".PHP_EOL;
}
if( $features & EventConfig::FEATURE_O1 ){
  echo "O1添加删除事件".PHP_EOL;
}
if( $features & EventConfig::FEATURE_FDS ){
  echo "任意文件描述符,不光socket".PHP_EOL;
}

运行结果如下图所示:

小小装个逼总结一下,今儿这些个内容就是讲述event的基础三大类,下个篇章依然是围绕这三个家伙和IO操作结合到一起。

[原文地址:https://blog.ti-node.com/blog...]

[原文地址:https://blog.ti-node.com/blog...]

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29394.html

相关文章

  • PHP socket初探 --- 含着泪也要磕完libevent(三)

    摘要:无数个专业送给啦啦啦啦,开始码注意,将监听设置为非阻塞模式这里值得注意,我们声明两个数组用来保存事件和连接欢迎来到聊天室发言注意遵守当地法律法规使用全局的和非阻塞模式下,注意的写法会稍微特殊一些。 原文地址:https://t.ti-node.com/thread/... 这段时间相比大家也看到了,本人离职了,一是在家偷懒实在懒得动手,二是好不容易想写点儿时间全部砸到数据结构和算法那里...

    suxier 评论0 收藏0
  • PHP socket初探 --- 颤颤抖抖开篇libevent(一)

    摘要:原文地址正如标题所言,颤颤抖抖开篇。于是只能是你自己,把单子上的个快递逐次和收到的对比一遍,然后对比完毕后再把这个单子给了阿梅,然后阿梅继续等。剃光头前的阿梅,就是,不敢正眼看老板娘一眼。剃光头后的阿梅,就是,可徒手接魔鬼队的死亡之球。 [原文地址:https://blog.ti-node.com/blog...] 正如标题所言,颤颤抖抖开篇epoll。颤颤抖抖的原因大概也就是以前几乎...

    levinit 评论0 收藏0
  • PHP socket初探 --- select系统调用

    摘要:原文地址在初探先从一个简单的服务器开始中依次讲解了三个逐渐进步的服务器只能服务于一个客户端的服务器利用可以服务于多个客户端的额服务器利用预派生进程服务于多个客户端的服务器最后一种服务器的进程模型基本上的大概原理其实跟我们常用的是非常 [原文地址:https://blog.ti-node.com/blog...] 在<PHP socket初探 --- 先从一个简单的socket服务器开始...

    springDevBird 评论0 收藏0
  • PHP socket初探 --- 关于IO的一些枯燥理论

    摘要:原文地址要想更好了解编程,有一个不可绕过的环节就是在中,一切皆文件实际上要文件干啥不就是读写么所以,这句话本质就是才是王道用的打开文件关闭文件读读写写,这叫本地文件在编程中,本质就是网络所以,在开始进一步的编程前,我们必须先从概念上认识好 [原文地址:https://blog.ti-node.com/blog...] 要想更好了解socket编程,有一个不可绕过的环节就是IO.在Lin...

    sf190404 评论0 收藏0
  • PHP多进程初探 --- 进程间通信三事

    摘要:多进程通信之一命名管道。多进程通信之三信号量与共享内存。共享内存是最快是进程间通信方式,因为个进程之间并不需要数据复制,而是直接操控同一份数据。的一些书籍中甚至不建议新手轻易使用这种进程间通信的方式,因为这是一种极易产生死锁的解决方案。 [原文地址:https://blog.ti-node.com/blog...] 往往开启多进程的目的是为了一起干活加速效率,前面说了不同进程之间的内存...

    CollinPeng 评论0 收藏0

发表评论

0条评论

jokester

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<