<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[沧海一粟]]></title> 
<link>http://www.dzhope.com/index.php</link> 
<description><![CDATA[Web系统架构与服务器运维,php开发]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[沧海一粟]]></copyright>
<item>
<link>http://www.dzhope.com/post//</link>
<title><![CDATA[ PHP后台守护进程的实现方式（Linux环境）]]></title> 
<author>jed &lt;jed521@163.com&gt;</author>
<category><![CDATA[服务器技术]]></category>
<pubDate>Thu, 12 Jan 2017 06:29:59 +0000</pubDate> 
<guid>http://www.dzhope.com/post//</guid> 
<description>
<![CDATA[ 
	　　应用场景<br/>　　<br/>　　某些情况下，我们需要持续的周期性的提供一些服务，比如监控内存或cpu的运行状况，这些应用与客户端是没有关系的，不是说客户端（如web界面，手机app等）关闭了，我们就不监控内存或cpu了，为了应对这种业务场景，后台守护进程就可以派上用场了。<br/>　　<br/>　　所需环境<br/>　　<br/>　　Linux<br/>　　<br/>　　实现方式<br/>　　<br/>　　1. 准备php脚本<br/>　　<br/>　　在/usr/local/src/目录下，新建一个daemon.php脚本文件，内如如下：<br/><br/><div class="code"><br/>&lt;?php&nbsp;&nbsp;<br/>&nbsp;&nbsp;<br/>Class Daemon&#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/** <br/>&nbsp;&nbsp;&nbsp;&nbsp; * 初始化一个守护进程 <br/>&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception <br/>&nbsp;&nbsp;&nbsp;&nbsp; */&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;public function init()&#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//创建一个子进程&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$pid = pcntl_fork();&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($pid == -1) &#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new Exception(&#039;fork子进程失败&#039;);&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; elseif ($pid &gt; 0) &#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//父进程退出,子进程变成孤儿进程被1号进程收养，进程脱离终端&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(0);&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//创建一个新的会话，脱离终端控制，更改子进程为组长进程&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sid = posix_setsid();&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($sid == -1) &#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new Exception(&#039;setsid fail&#039;);&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//修改当前进程的工作目录，由于子进程会继承父进程的工作目录，修改工作目录以释放对父进程工作目录的占用。&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chdir(&#039;/&#039;);&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/** <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 通过上一步，我们创建了一个新的会话组长，进程组长，且脱离了终端，但是会话组长可以申请重新打开一个终端，为了避免 <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 这种情况，我们再次创建一个子进程，并退出当前进程，这样运行的进程就不再是会话组长。 <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$pid = pcntl_fork();&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($pid == -1) &#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new Exception(&#039;fork子进程失败&#039;);&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; elseif ($pid &gt; 0) &#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//再一次退出父进程，子进程成为最终的守护进程&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(0);&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//由于守护进程用不到标准输入输出，关闭标准输入，输出，错误输出描述符&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fclose(STDIN);&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fclose(STDOUT);&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fclose(STDERR);&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;<br/>&#125;&nbsp;&nbsp;<br/>&nbsp;&nbsp;<br/>$daemon = new Daemon();&nbsp;&nbsp;<br/>$daemon-&gt;init();&nbsp;&nbsp;<br/>&nbsp;&nbsp;<br/>//处理业务代码&nbsp;&nbsp;<br/>while(true) &#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;file_put_contents(&#039;/usr/local/src/log.txt&#039;, time().PHP_EOL, FILE_APPEND);&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;sleep(5);&nbsp;&nbsp;<br/>&#125;&nbsp;&nbsp;<br/></div><br/><br/>　　该脚本的作用，就是每隔5秒，向日志文件中写入一个时间戳，当然，这个只是一个简单的示例，具体应用中，我们还需要根据业务的不同，编写具体的业务处理代码。<br/>　　<br/>　　2. 以后台方式运行php脚本<br/>　　<br/>　　在命令行下，输入：<br/><br/>　　<div class="code"><br/>　　nohup php /usr/local/src/daemon.php &amp;<br/>　　</div><br/>　　3. 查看日志输出<br/>　　<br/>　　在命令行下，输入：<br/>　　<div class="code"><br/>　　tail -f /usr/local/src/log.txt<br/>　　</div><br/>　　我们将会看到如下信息：<br/>　　<br/>　　4. 关闭php后台进程<br/>　　<br/>　　首先，我们需要查出该进程的PID，命令：<br/>　　<div class="code"><br/>　　ps -ef &#124; grep &quot;php /usr/local/src/daemon.php&quot;<br/>　　</div><br/>　　然后，通过这个PID把该进程kill掉<br/>　　<div class="code"><br/>　　kill -9 22767<br/>　　</div><br/>　　其中，22767就是php后台进程的PID号。<br/>　　<br/>　　5. 开机自启<br/>　　<br/>　　通过前面的步骤，我们知道如何开启和关闭一个php进程，但是，在实际的应用中，我们不可能每次都是手动开启，这样我们就会损失掉一部分业务数据，所以我们必须要让该进程开机自动运行，步骤如下：<br/>　　<br/>　　在/etc/rc.local文件中，将nohup php /usr/local/src/daemon.php &这个命令加入即可。<br/>Tags - <a href="http://www.dzhope.com/tags/php/" rel="tag">php</a> , <a href="http://www.dzhope.com/tags/%25E5%25AE%2588%25E6%258A%25A4%25E8%25BF%259B%25E7%25A8%258B/" rel="tag">守护进程</a>
]]>
</description>
</item><item>
<link>http://www.dzhope.com/post//#blogcomment</link>
<title><![CDATA[[评论]  PHP后台守护进程的实现方式（Linux环境）]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://www.dzhope.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>