php进程通信

php高级应用之进程控制及进程间通讯

2013-11-26 13:41:58 walkor 阅读数 7907更多

分类专栏: PPM php WorkerMan

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/u012810515/article/details/16961603

很少有用php写服务的,然而有些场景又要求能有一个这样的服务器程序,它能够与php无缝结合,并且提供高可靠靠性能的服务,并且提供现有架构所没有的一些高级特性,例如支持自定义协议,支持长连接等等。PPM(PHP-Process-Manager)是我用PHP开发的一款进程管理框架,集成了socket服务功能,无需安装nginx、apache、php-fpm,只需要安装php-cli即可。支持libevent事件轮询库,支持服务平滑重启,支持磁盘文件监控及自动更新,支持各种协议包括自定义协议,最主要的由于是用php写的,它能与php无缝结合,非常适合用php写后端业务逻辑。

 

代码已经开源,更名为WorkerMan,代码在www.workerman.net,或者在https://github.com/walkor上下载

 

下面我讲下PPM进程控制与管理的做法

为了充分发挥服务器多核的优势,socket服务都会采用多线程及多进程的模型对外提供服务。用php写服务必然涉及到进程管理或这线程管理方面的东西,由于PPM使用的是多进程模型,这里主要讲下php进程控制与管理方面的内容。

1、如何成为daemon程序?

2、如何实现多进程?

3、如何监控子进程是否退出?

4、进程间如何通信?

 

以下都是在linux环境中(windows不支持php多进程),并且是在php-cli模式下。

1、如何成为daemon程序

废话不多说,直接上代码

 

 
  1.         // 设置umask

  2. umask(0);

  3. // fork一次

  4. $pid = pcntl_fork();

  5. if(-1 == $pid)

  6. {

  7. // 出错退出

  8. exit("Daemonize fail ,can not fork");

  9. }

  10. elseif($pid > 0)

  11. {

  12. // 父进程,退出

  13. exit(0);

  14. }

  15. // 子进程使之成为session leader

  16. if(-1 == posix_setsid())

  17. {

  18. // 出错退出

  19. exit("Daemonize fail ,setsid fail");

  20. }

  21.         // 现在已经是daemon进程了

 

2、如何实现多进程

类似上面使用pcntl_fork函数,也不多说,看代码

 

 
  1. $pid = pcntl_fork();

  2. if($pid > 0)

  3. {

  4. // 父进程

  5.  
  6. }

  7. elseif(0 == $pid)

  8. {

  9. // 子进程

  10. }

  11. else

  12. {

  13. // 出错

  14. }

 

 

3、如何监控子进程是否退出

 

php监控子进程退出有几种办法

1、监听SIGCHLD信号

在linux系统中,一个进程终止或者停止时,它的父进程会收到一个SIGCHLD信号,在php中可以用

pcntl_sigwaitinfo、pcntl_sigtimedwait、pcntl_signal等函数都检测到此信号。父收到SIGCHLD信号,说明有子进程退出了。要注意的是信号可能会重叠,当有多个SIGCHLD信号到达父进程时,父进程可能只检测到一个SIGCHLD信号。需要循环用pcntl_wait/pcntl_waitpid函数检测到底有几个子进程退出以及退出的状态。

一个监控SIGCHLD信号的示例

 

 
  1. pcntl_sigtimedwait(array(SIGCHLD), $siginfo);

  2. while(($pid = pcntl_waitpid(-1, $status, WUNTRACED | WNOHANG)) != 0){

  3. // 退出的子进程pid

  4. if($pid>0){

  5. // pid为$pid的子进程退出了,这里可以重新pcntl_fork一个新的子进程

  6. }

  7. else{

  8. // 出错了

  9. }

  10. }

上面这个例子进程会阻塞在pcntl_sigtimedwait上,同时我们可以用pcntl_sigtimedwait监听更多的信号,例如同时监听SIGINT终止信号来实现整个服务的停止,同时监听SIGHUP来实现服务的平滑重启等等

 

 

 

2、直接调用pcntl_wait/pcntl_waitpid监控

 

 
  1. while(($pid = pcntl_waitpid(-1, $status, WUNTRACED)) != 0){

  2. // 退出的子进程pid

  3. if($pid>0){

  4. // pid为$pid的子进程退出了,这里可以重新pcntl_fork一个新的子进程

  5. }

  6. else{

  7. // 出错了

  8. }

  9. }

这里和上面的例子少了一个pnntl_sigtimedwait调用,直接使用pcntl_waitpid,注意pcntl_waitpid第三个参数没有传WNOHANG,则整个进程会阻塞在pcntl_waitpid上。

 

 

3、在进程间建立socket或者管道

在进程间建立socket或者管道,然后用select等IO复用技术监听socket或者管道可读,如果可读但是没有读出数据,那么说明进程间的socket或者管道已经断开了,很可能对方进程已经退出了。

 

 
  1. // 创建管道

  2. $channel = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);

  3. stream_set_blocking($channel[0], 0);

  4. stream_set_blocking($channel[1], 0);

  5. // 创建子进程

  6. $pid = pcntl_fork();

  7. // 父进程

  8. if($pid > 0)

  9. {

  10. fclose($channel[1]);

  11. $write = $e = null;

  12. while(1)

  13. {

  14. $read = array($channel[0]);

  15. if(@stream_select($read, $write, $e, 1))

  16. {

  17. foreach($read as $channel_to_check)

  18. {

  19. if('' == fread($channel_to_check))

  20. {

  21. // $channel_to_check(这里是channel[0])对应进程可能退出了

  22. }

  23. }

  24. }

  25. }

  26. }

  27. // 子进程

  28. elseif($pid === 0)

  29. {

  30. fclose($channel[0]);

  31.  
  32. }

上面的例子整个进程会阻塞在stream_select调用上面。建立socket监听可读事件,不局限与父子进程间监控进程退出,任何进程间建立链接后,都可以实现监控进程退出事件,而且进程间可以通过这个链接实现进程间通讯。

 

 

 

4、定时发送信号0检测

 

 
  1. while(1)

  2. {

  3. // 使用posix_kill需要当前进程所有者与被检测$pid所有者是同一个或者当前进程所有者拥有足够的权限

  4. if(!posix_kill($pid, 0))

  5. {

  6. // 进程$pid已经退出了

  7. }

  8. sleep(1);

  9. }

这个方法最简单,只要有权限,它可以检测任何进程是否存活。缺点是不能及时的检测到进程退出。

 

 

4、进程间如何通信

PHP可用的进程间通讯方法很多

1、共享内存 shm_*、shmop_*   // 注意多进程写的时候要考虑互斥

2、消息队列msg_*                         // 直接使用系统的消息队列,简单高效,不用考虑互斥问题

3、信号量sem_*                             // 用于互斥使用某个资源

4、管道 PIPE管道、全双工管道、FIFO命名管道

5、socket 命名、无名、unix socket                      

等等..

具体使用哪种,看实际需要而定。

 

代码已经开源,更名为WorkerMan,代码在www.workerman.net,或者在https://github.com/walkor上下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值