从proc_open()打开的两个进程说起
起因
最近工作不太紧张,于是看起了《PHP Reactive Programming》这本书,其中举了个Chat Server的例子。
这是一个Cli App,默认启动一个Server Manager,根据Stdin的输入进行Chat Server的创建,Server Manager建立一个Unix Socket Server,其创建的Chat Server通过连接Socket Server与Server Manager进行状态通信;而Chat Server监听服务器的某个指定端口,创建一个WebSocket Server;其他客户端通过连接这个WebSocket Server进行Chat动作,而Chat Server会实时将在线、聊天数量上报给Server Manager。
用的当然是书中提到的Reactive Programming,使用了PHP的stream族函数进行非阻塞编程。
其中,由于之前对黄旭说过的socketpair比较感兴趣,所以详细看了一下Server Manager创建Chat Server的部分。
这一部分采用了symfony/process组件,对Chat Server的创建并不是通过fork
的方式进行的,而是通过proc_open
进行的。
之后,参照proc_open()文档中给的例子,在不同的机器上实验了一下,这就试出了毛病。
问题
出现问题的操作系统是去年年底新装的Xubuntu 16.04/PHP 5.6
,执行php sleep.php
父进程下面竟然出现了两个进程。
然后,换到测试机器上面(CentOS 6/PHP 5.5
),执行相同的代码,父进程下面只挂着一个sleep 100
的子进程,这个是正确的。
排查
初始以为是PHP版本造成的问题,然后Ubuntu和CentOS都换用PHP 7.0版本执行代码,然后结果相同,所以排除PHP版本造成的问题。
那么会不会是服务器版本造成的问题呢?
我想了一下,Ubuntu上面多出的一个进程是sh -c
的进程,那么我们手工执行一下sh -c 'sleep 100'
会发生什么呢?
于是在Ubuntu上面得到下面的结果,仍然是两个进程:
然而在CentOS上面,得到结果却只有一个sleep
的进程:
那么,会不会是sh
的问题呢?
解决
突然想起来,很久很久以前安装Ubuntu操作系统的时候,sh
默认的都是dash
,一般都要改成bash
,会不会是dash
造成的呢?
于是,在Ubuntu上面手工执行bash -c 'sleep 100'
和dash -c 'sleep 100'
,结果分别如下:
bash
dash
然后查看sh
,果然是软链接到dash
上面了。
将sh
的软链接改到bash
上面,PHP代码按照预期的结果执行下去了~
小结
PHP的proc_open
系列函数在Linux操作系统中应该是通过系统默认的sh -c
命令进行执行的,要把不同的sh
带来的结果考虑进去。