1.什么是保护进程
保护进程是脱离于终端并且在后台运行的进程。保护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上表示并且进程亦不会被任何终端所产生的终端信息所打断。
例如 apache, nginx, redis, memcache, mysql 都是保护进程, 简而言之, 保护进程(daemon)便是始终在后台运行的进程(daemon)。
2.为何研发保护进程
非常多程序以服务形式存在, 他无终端或UI交互, 它可能采用其他方式与其他程序交互, 如TCP/UDP Socket, UNIX Socket, fifo。程序一旦起步便进入后台, 直到满足要求他便起始处理任务。
3.何时采用保护进程研发应用程序
以我当前的需要为例, 我需要运行一个程序, 而后监听某端口, 连续接收服务端发起的数据, 而后对数据分析处理, 再将结果写入到数据库中; 我采用ZeroMQ实现数据收发。
倘若我不采用保护进程方式研发该程序,程序一旦运行就会占用当前终端窗框,还有受到当前终端键盘输入影响,有可能程序误退出。
4.保护进程的安全问题
咱们期盼程序在非超级用户运行,这般一旦因为程序显现漏洞被黑客掌控,攻击者只能继承运行权限,而没法得到超级用户权限。
咱们期盼程序只能运行一个实例,不运行同期开启两个以上的程序,由于会显现端口冲突等等问题。
运用场景
保护进程通常用于监控其他程序运行状况和执行按时任务。
创建保护进程
起始 -> fork()创建子进程 exit()使父进程退出 -> setsid() 创建新会话 -> chdir("/") 设置工作目录 -> umask(0) 重设文件权限掩码 close() 关闭文件描述符 -> 结束
下面以PHP的实现方式为例来讲明。在说明之前先介绍几个PHP函数。如下:
pcntl_fork(): 在当前进程内创建一个子进程。成功时, 在父进程执行线程内返回产生的子进程的PID, 在子进程执行线程内返回0。失败时, 在父进程上下文返回-1, 不会创建子进程, 并且会诱发一个PHP错误。
int pcntl_fork ( void )
实例:
<?php
$pid = pcntl_fork ();
//父进程和子进程都会执行下面代码
if($pid == - 1){
//错误处理:创建子进程失败时返回-1.
die( could not fork );
}elseif( $pid ) {
//父进程会得到子进程号,因此这儿是父进程执行的规律
pcntl_wait ( $status ); //等待子进程中断,防止子进程作为僵尸进程。
}else{
//子进程得到的$pid为0, 因此这儿是子进程执行的规律。
}
?>
posix_setuid(): 设置当前进程的操功效户
bool posix_setuid ( int $uid )
posix_setgid(): 设置当前进程的操功效户所属分组
bool posix_setpgid ( int $pid , int $pgid )
getmypid(): 获取当前 PHP 进程 ID。 获取当前 PHP 进程 ID。
int getmypid ( void )
posix_kill(): 向指定进程发送进程信号
bool posix_kill ( int $pid , int $sig )
pcntl_signal(): 安装一个信号处理器
bool pcntl_signal ( int $signo , callback $handler [, bool $restart_syscalls = true ] )
signo 信号编号。
handler 信号处理器能够是用户创建的函数或办法的名字, 亦能够是系统常量 SIG_IGN (译注:忽略信号处理程序)或 SIG_DFL(默认信号处理程序) .
Note: 重视当你运用一个对象办法的时候, 该对象的引用计数回增多使得它在你改变为其他处理或脚本结束之前是持久存在的。
restart_syscalls 指定当信号到达时系统调用重启是不是可用。
system(): 执行外边程序, 并且表示输出
string system ( string $command [, int &$return_var ] )
<?php
echo <pre>;
$last_line = system ( ls , $retval );
echo </pre>;
?>
PHP后台保护进程的实现方式(Linux环境)
应用场景
某些状况下, 咱们需要连续的周期性的供给有些服务, 例如监控内存或cpu的运行情况, 这些应用与客户端是无关系的, 不是说客户端(如web界面, 手机app等)关闭了, 咱们就不监控内存或cpu了,
为了应对这种业务场景, 后台保护进程就能够派上用场了。
所需环境
Linux
实现方式
1. 准备php脚本
在/usr/local/src/目录下, 新建一个daemon.php脚本文件, 内如如下:
<?php
Class Daemon{
/**
* 初始化一个保护进程
* @throws Exception
*/
public function init(){
//创建一个子进程
$pid = pcntl_fork();
if ($pid == -1) {
throw new Exception(fork子进程失败);
} elseif ($pid > 0) {
//父进程退出,子进程变成孤儿进程被1号进程收养,进程脱离终端
exit(0);
}
//创建一个新的会话,脱离终端掌控,更改子进程为组长进程
$sid = posix_setsid();
if ($sid == -1) {
throw new Exception(setsid fail);
}
//修改当前进程的工作目录,因为子进程会继承父进程的工作目录,修改工作目录以释放对父进程工作目录的占用。
chdir(/);
/**
* 经过上一步,咱们创建了一个新的会话组长,进程组长,且脱离了终端,然则会话组长能够申请重新打开一个终端,为了避免
* 这种状况,咱们再次创建一个子进程,并退出当前进程,这般运行的进程就再也不是会话组长。
*/
$pid = pcntl_fork();
if ($pid == -1) {
throw new Exception(fork子进程失败);
} elseif ($pid > 0) {
//再一次退出父进程,子进程作为最后的保护进程
exit(0);
}
//因为保护进程用不到标准输入输出,关闭标准输入,输出,错误输出描述符
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
}
}
$daemon = new Daemon();
$daemon->init();
//处理业务代码
while(true) {
file_put_contents(/usr/local/src/log.txt, time().PHP_EOL, FILE_APPEND);
sleep(5);
}
该脚本的功效, 便是每隔5秒, 向日志文件中写入一个时间戳, 当然, 这个只是一个简单的示例, 详细应用中, 咱们还需要按照业务的区别, 编写详细的业务处理代码。
2. 以后台方式运行php脚本
在命令行下, 输入:
nohup php /usr/local/src/daemon.php &
nohup: ignoring input and appending output to `nohup.out
nohup: failed to run command `/etc/nginx_check.sh: Permission denied
说明无权限
chmod +x /usr/local/src/daemon.php
nohup: ignoring input and appending output to ‘nohup.out’
倘若只显现这种结果: 说明保护进程执行成功, 运用ctrl+c 退出
3. 查看日志输出
tail -f /usr/local/src/log.txt
咱们将会看到如下信息:
1471917997
1471918016
1471918026
4. 关闭php后台进程
首要, 咱们需要查出该进程的PID, 命令:
ps -ef | grep "php /usr/local/src/daemon.php" (常用的参数 ps -A | grep "daemon.php")
经过这个PID把该进程kill掉
kill -9 22767
其中, 22767便是php后台进程的PID号。
5. 开机自启
经过前面的过程, 咱们晓得怎样开启和关闭一个php进程, 然则, 在实质的应用中, 咱们不可能每次都是手动开启, 这般咱们就会损失掉一部分业务数据, 因此咱们必须要让该进程开机自动运行, 过程如下:
在/etc/rc.local文件中, 将nohup php /usr/local/src/daemon.php &这个命令加入就可。
重视: 保护进程文件加载尽可能采用绝对位置, 能够运用 __dir__ 代替;
|