php万字码出完美守护进程详解

目录
  • 前事提要
  • 基本概念
  • 基本特点
  • 创建守护进程要求

前事提要

上期我们详细学习了会话的概念以及用法,会话,进程组,终端的理解对本篇讲述的守护进程极其重要,如还不理解相关概念建议翻看我往期关于会话,进程组,终端文章。

基本概念

守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程。通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。并且不跟任何的控制终端关联,如果想让某个进程不因为用户或中断或其他变化而影响,那么就必须把这个进程变成一个守护进程。

常见的守护进程包括系统日志进程syslogd、 web服务器httpd、任务规划守护进程crond,数据库服务器mysqld等。一般采用以 d 结尾的名字。

查看系统守护进程命令 ps -efj

基本特点

生存周期长[非必须],一般操作系统启动的时候就启动,关闭的时候关闭。

守护进程和终端无关联,也就是他们没有控制终端,所以当控制终端退出,也不会导致守护进程退出。

守护进程是在后台运行,不会占着终端,终端可以执行其他命令

守护进程的父进程是1号进程,也就是init进程;

  • 在Linux中 , 大概有三种方式实现脚本后台化 :

1 . 在命令后添加一个&符号 , 比如 php task.php & . 这个方法的缺点在于 如果terminal终端关闭 , 无论是正常关闭还是非正常关闭 , 这个php进程都会随着终端关闭而关闭 , 其次是代码中如果有echo或者print_r之类的输出文本 , 会被输出到当前的终端窗口中 .

2 . 使用nohup命令 , 比如 nohup php task.php & . 默认情况下 , 代码中echo或者print_r之类输出的文本会被输出到php代码同级目录的nohup.out文件中 . 如果你用exit命令或者关闭按钮等正常手段关闭终端 , 该进程不会被关闭 , 依然会在后台持续运行 . 但是如果终端遇到异常退出或者终止 , 该php进程也会随即退出 . 本质上 , 也并非稳定可靠的daemon方案 .

3 . 使用fork和setsid , 我暂且称之为 : *nix解决方案

创建守护进程要求

  • 1. 设置文件创建屏蔽字 umask(0)

文件创建屏蔽字是指屏蔽掉文件创建时的对应位(umask() 控制系统文件和目录默认权限)。由于使用fork系统调用新建的子进程继承了父进程的文件创建掩码,这就给该子进程使用文件带来了诸多的不便。因此,把文件创建掩码设置为0,可以大大增强该守护进程的灵活性。

  • 2. 调用fork,父进程退出(exit);

如果该守护进程是作为一条简单的shell命令启动的,那么父进程终止使得shell认为该命令已经执行完毕;保证子进程不是一个进程组的组长进程,为什么要保证不是进程组组长呢? 因为进程组组长调用setsid创建会话会报错;

  • 3. 子进程调用setsid 函数来创建会话

先介绍一下Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。

控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。方法是在第2点的基础上,调用setsid()使进程成为会话组长:

setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。

调用setsid有3个作用:

让进程摆脱原会话的控制;

让进程摆脱原进程组的控制;

让进程摆脱原控制终端的控制

  • 4. 把守护进程工作目录设置为根目录 chdir(“/”);

从父进程继承过来的工作目录可能在一个挂载的文件系统中。由于守护进程通常在系统再引导之前是一直存在的,所以如果守护进程的当前工作目录在一个挂载的文件系统中,会导致该文件系统不能被卸载。

  • 5.把一些文件描述符关闭 【标准输入,标准输出,标准错误】

文件描述符:用来标识一个文件。当你打开一个存在的文件或者创建一个新文件,操作系统都会返回这个文件描述符。后续对这个文件的操作的一些函数,都会用到这个文件描述符作为参数。

Linux中三个特殊的文件描述符,数字分别为0,1,2:

0:标准输入[键盘],对应的符号常量叫 STDIN_FILENO

1:标准输出[屏幕],对应的符号常量叫 STDOUT_FILENO

2:标准错误[屏幕],对应的符号常量叫STDERR_FILENO

进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。

  • 6. 当调用setsid函数后,一般会在创建一个子进程,让会话首进程退出,确保该进程不会再获得控制终端

(1)调用一次fork的作用:

第一次fork的作用是让shell认为这条命令已经终止,不用挂在终端输入上,还有就是为了后面的setsid服务,因为调用setsid函数的进程不能是进程组组长,如果不fork出子进程,则此时的父进程是进程组组长,就无法调用setsid。当子进程调用完setsid函数之后,子进程是会话组长也是进程组组长,并且脱离了控制终端,此时,不管控制终端如何操作,新的进程都不会收到一些信号使得进程退出。

(2)第二次fork的作用:

虽然当前关闭了和终端的联系,但是后期可能会误操作打开了终端。

只有会话首进程能打开终端设备, 也就是再fork一次,再把父进程退出,再次fork的子进程作为守护进程继续运行,保证了该守护进程不再是会话的首进程。

第二次不是必须的,是可选的。

  • 7.编写一个守护进程
<?php
// 1. 设置文件创建屏蔽字
umask(0);
// 2. fork 子进程
$pid = pcntl_fork();

if($pid > 0){
        print("父进程退出\n");
        exit(0);
}
//3. 设置当前子进程为会话首进程,进程组长,断开与终端的连接,成为后台进程
if(-1 === posix_setsid()){
        print("sid err \n");
}
// 4. 把守护进程工作目录设置为根目录
chdir("/");
//已经成为守护进程~\(≧▽≦)/~啦
while(1){
echo "test".PHP_EOL;
sleep(2);
}

将文件保存为daemon.php,然后php daemon.php执行文件,嗯,执行结果却有些奇怪,大概类似于下图:

即便你按Ctrl+C都没用,终端在不断输出test,唯一办法就是关闭当前终端窗口然后重新开一个,为什么会这样,这就涉及到我们上面提到的第5点,需要关闭继承过来的标准输出,输入,错误,这样我们的daemon程序不可以再将终端窗口当作默认的标准输出了。

<?php
// 设置文件创建屏蔽字
umask(0);
// 第一次fork 子进程
$pid = pcntl_fork();
if($pid > 0){
        print("父进程退出\n");
        exit(0);
}
//设置当前子进程为会话首进程,进程组长,断开与终端的连接,成为后台进程
if(-1 === posix_setsid()){
        print("sid err \n");
}
//第二次fork 彻底断开控制终端
$pid = pcntl_fork();
if($pid > 0){
	exit(0);//让会话首进程退出
}
// 把守护进程工作目录设置为根目录
chdir("/");
// 关闭标准输入,标准输出,标准错误,linux 中使用数字表示文件描述符也就是 0,1,2
fclose(STDIN);//0
fclose(STDOUT);//1
fclose(STDERR);//2
//当关掉以上标准输出,标准输入,标准错误之后,如果后面要对文件操作(比如打开一个文件,写入,创建)它返回的文件描述符从0开始,这样可能造成未知异常
//为了避免问题,我们使用输出从定向到 /dev/null 空设备文件解决这个问题,重新设置0,1,2 文件描述符用来代替标准输入,标准输出,标准错误,往 /dev/null 写入数据会被丢弃,这样就不会向终端输出数据了。
$stdin = fopen("/dev/null",'a');
$stdout = fopen("/dev/null",'a');
$stderr = fopen("/dev/null", 'a');
//已经成为守护进程~\(≧▽≦)/~啦
while(1){
echo "test".PHP_EOL;
sleep(2);
}

空设备

/dev/null : 是一个特殊的设备文件,它丢弃一切写入其中的数据(像黑洞一些)例如:echo “大雷编程” > /dev/null 输出重定向文件到黑洞(无任何输出)。

我们一般把守护进程的标准输入、标准输出重定向到空设备(黑洞),从而确保守护进程不从键盘接收任何东西,也不把输出结果打印到屏幕。

到此这篇关于php万字码出完美守护进程详解的文章就介绍到这了,更多相关php守护进程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 分享PHP守护进程类

    用PHP实现的Daemon类.可以在服务器上实现队列或者脱离 crontab 的计划任务.  使用的时候,继承于这个类,并重写 _doTask 方法,通过 main 初始化执行. <?php class Daemon { const DLOG_TO_CONSOLE = 1; const DLOG_NOTICE = 2; const DLOG_WARNING = 4; const DLOG_ERROR = 8; const DLOG_CRITICAL = 16; const DAPC_PATH =

  • php实现简单的守护进程创建、开启与关闭操作

    本文实例讲述了php实现简单的守护进程创建.开启与关闭操作.分享给大家供大家参考,具体如下: 前提要安装有pcntl扩展,可通过php -m查看是否安装 <?php class Daemon { private $pidfile; function __construct() { $this->pidfile = dirname(__FILE__).'/daemontest.pid'; } private function startDeamon() { if (file_exists($th

  • PHP守护进程的两种常见实现方式详解

    本文实例讲述了PHP守护进程的两种常见实现方式.分享给大家供大家参考,具体如下: 第一种方式,借助 nohup 和 &  配合使用. 在命令后面加上 & 符号, 可以让启动的进程转到后台运行,而不占用控制台,控制台还可以再运行其他命令,这里我使用一个while死循环来做演示,代码如下 <?php while(true){ echo time().PHP_EOL; sleep(3); } 用 & 方式来启动该进程 [root@localhost php]# php deadlo

  • 如何写php守护进程(Daemon)

    守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种很有用的进程.php也可以实现守护进程的功能. 一.基本概念 进程: 每个进程都有一个父进程,子进程退出,父进程能得到子进程退出的状态. 进程组:每个进程都属于一个进程组,每个进程组都有一个进程组号,该号等于该进程组组长的PID 二.守护编程要点 1. 在后台运行               为避免挂起控制终端将Daemon放入后台执行.方法是在进程中调用fork使

  • PHP实现守护进程的示例代码

    目录 前言 成为守护进程的步骤 实现 说明 创建子进程并退出父进程 创建新的会话 重设文件掩码 改变工作目录 关闭标准输入输出 其他 注意事项 前言 写 PHP CLI 程序的老司机们可能经常会写一些常驻进程,比如消息队列消费者进程,这些进程会一直运行,除非要发版,不然一般不会重启的,所以程序程序是不可能由我们通过 ssh 登录到服务器上通过终端来直接启动的(因为一旦断开 ssh 进程就退出了),常见的做法就是用 systemd 或者 supervisor 来使其成为 守护进程,这样进程就可以一

  • PHP守护进程实例

    php也是可以直接进行守护进程的启动与终止的,相对于shell来说会简单很多,理解更方便,当然了php的守护进程要实现自动重启还是要依赖于shell的crontab日程表,每隔一段时间去执行一次脚本看脚本是否需要重启,如果需要则杀掉进程删除RunFile文件,重新启动并在RunFile文件中写入pid. 复制代码 代码如下: <?php       function start($file){     $path = dirname(__FILE__).'/';     $runfile = $

  • PHP程序守护进程化实现方法详解

    一般Server程序都是运行在系统后台,这与普通的交互式命令行程序有很大的区别.glibc里有一个函数daemon.调用此函数,就可使当前进程脱离终端变成一个守护进程,具体内容参见man daemon.PHP中暂时没有此函数,当然如果你有兴趣的话,可以写一个PHP的扩展函数来实现. PHP命令行程序实现守护进程化有2种方法: 一 .使用nohup nohup php myprog.php > log.txt & 这里就实现了守护进程化. 单独执行 php myprog.php,当按下ctrl

  • php脚本守护进程原理与实现方法详解

    本文实例讲述了php脚本守护进程原理与实现方法.分享给大家供大家参考,具体如下: 思路: 1. while 循环,若当前没有数据要操作可以休眠: 2. crontab 脚本每隔固定时间段执行该脚本,执行时先检测是否已在执行,若无 执行,有则 跳过. 3. nohup  后台执行 4. flock -xn  加锁 实例: 要执行代码:index.php <?php set_time_limit(0); //死循环 while(1) { $message = '1111111' . "\n&q

  • PHP扩展程序实现守护进程

    一般Server程序都是运行在系统后台,这与普通的交互式命令行程序有很大的区别.glibc里有一个函数daemon.调用此函数,就可使当前进程脱离终端变成一个守护进程,具体内容参见man daemon.PHP中暂时没有此函数,当然如果你有兴趣的话,可以写一个PHP的扩展函数来实现. PHP命令行程序实现守护进程化有2种方法: 一 .使用nohup 复制代码 代码如下: nohup php myprog.php > log.txt & 这里就实现了守护进程化. 单独执行 php myprog.

  • linux 守护进程详解及建立守护进程

    linux 守护进程详解及建立守护进程 守护进程是一种后台运行并且独立于所有终端控制之外的进程. 守护进程的启动 要启动一个守护进程,可以采取一下几种方式: 在系统期间通过系统的初始化脚本启动守护进程.这些脚本通常在目录etc/rc.d下,通过它们所启动的守护进程具有超级用户的权限.系统的一些基本服务通常都是通过这种方式启动的. 很多网络服务程序都是由inetd守护程序启动的.它监听各种网络请求,如telnet.ftp等,在请求到达时启动相应的服务器程序(telnet server,ftp se

  • IDEA部署jeesite3完美运行教程详解

    jeesite3的官方文档非常坑爹,按那个部署是不能正常运行的,IDEA2018/2019完美运行教程如下: 1. 从geiee(码云)上下载代码,命令:git clone https://gitee.com/thinkgem/jeesite 2. 打开IDEA,选择open,导入克隆的 jeesite项目 3. 修改 jeesite\jeesite\src\main\resources\jeesite.properties 中的数据库用户名和密码,改成自己电脑的即可,如果有提示需要MAVEN下

  • jQuery validate+artdialog+jquery form实现弹出表单思路详解

    功能描述: 在页面弹出一个form表单,ajax无刷新提交表单,表单需通过验证. 适用范围: 适用于在列表页面新增,修改记录. 需要加载的js文件: jquery.min.js artDialog.js iframeTools.js jquery.form.js jquery.validate.js 实现思路: 在页面中将表单放到一个隐藏的容器中,用artdialog弹出该form并对form加上jqueryvalidate验证,提交采用jqueryform ajax提交,由于都是用现成的插件写

  • php源码 fsockopen获取网页内容实例详解

    PHP fsockopen函数说明: Open Internet or Unix domain socket connection(打开套接字链接) Initiates a socket connection to the resource specified by target . fsockopen() returns a file pointer which may be used together with the other file functions (such as fgets(

  • 使用微信小程序开发弹出框应用实例详解

    view class="container" class="zn-uploadimg"> <button type="primary"bindtap="showok">消息提示框</button> <button type="primary"bindtap="modalcnt">模态弹窗</button> <button typ

  • java打印出菱形图案实例详解

    第一步:首先对图像进行解析 想要打印该图形必须要进行多层循环嵌套,分两个部分进行打印. 第一部分为上半部分前四行,他们是递增的关系,后半部分后三行为递减关系,由此可以得出我们需要写两个打的循环.并且由于"*"位置的关系,我们必须带入空格同时打印.所以每个部分需要两个循环控制,即两个大循环每个里面嵌套两个小循环总计四个循环. 第二部:对数字进行分析 在分析之前,我们必须明白外层循环控制行数,内层循环控制列数,因此我们需要分析他的行和列. 示例代码如下: class ForForTest

  • C# 图片与Base64码的相互转化问题(代码详解)

    Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法.可查看RFC2045-RFC2049,上面有MIME的详细规范. Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息.采用Base64编码具有不可读性,需要解码后才能阅读. Base64由于以上优点被广泛应用于计算机的各个领域,然而由于输出内容中包括两个以上"符号类"字符(+, /, =),不同的应用场景又分别研制了Base64

  • HashMap源码中的位运算符&详解

    引言 最近在读HashMap源码的时候,发现在很多运算符替代常规运算符的现象.比如说用hash & (table.length-1) 来替代取模运算hash&(table.length):用if((e.hash & oldCap) == 0)判断扩容后元素的位置等等. 1.取模运算符%底层原理 ​总所周知,位运算&直接对二进制进行运算:而对于取模运算符%:a % b 相当于 a - a / b * b,底层实际上是除法器,究其根源也是由底层的减法和加法共同完成.所以其运行效

  • Node.js中创建和管理外部进程详解

    Node被设计用来高效的处理I/O操作,但是你应该知道,有些类型的程序并不适合这种模式.比如,如果你打算用Node处理一个CPU密集的任务,你可能会堵塞事件循环,并因此降低了程序的响应.替代办法是,把CPU密集的任务分配给一个单独的进程来处理,从而释放事件循环.Node允许你产生进程,并把这个新进程做为它父进程的子进程.在Node里,子进程可以和父进程进行双向通信,而且在某种程度上,父进程还可以监控和管理子进程. 另外一种需要使用子进程的情况是,当你想简单地执行一个外部命令,并让Node获取命令

  • 搭建Tomcat 8源码开发环境的步骤详解

    前言 最近在网上搜索了很多关于tomcat源码环境搭建的文章,发现按照文章的步骤,几乎都启动不了,于是自己尝试搭建,下面是搭建的方法. 基础环境搭建 1.下载tomcat源代码,我这里是通过svn的方式下载的,svn下载地址 2.下载安装maven工具,这里我就不多说了,安装说明太多了,自己网上找. 3.IDE,我这里使用idea 生成maven工程 我的代码本地目录是: /Users/helanzhou/Documents/helanzhou/java/Tomcat/tomcat8/tomca

随机推荐

其他