周梦康 发表于 2015-10-16 13831 次浏览 标签 : Linux

什么是守护进程?

  1. 守护进程是再后台运行不受终端控制的进程,通常情况下守护进程在系统启动时运行;

  2. 守护进程的名称通常以d结尾,比如httpd,sshd等。

今天对比参考了下《UNIX 环境高级编程》,书上在创建的步骤更加细致,比如需要调用umask,通过getrlimit获取最高文件描述符值,下面的演示代码中,由于知道就三个文件描述符就没有写那么仔细,更加权威的还是要参考《UNIX 环境高级编程》(2015.10.17)

如何才能创建守护进程?

  1. 调用fork创建新进程,这个子进程的就是将会成为守护进程的进程;

  2. 在主进程中调用exit

  3. 在子进程中调用setsid创建新的会话期;

  4. 将当前目录改为根目录(如果把当前目录作为守护进程的目录,当前目录不能被卸载,它作为守护进程的工作目录了)。

  5. 将标准输入,标准输出,标准错误重定向到/dev/null

基于 linux 操作系统对守护进程的理解学习

动手练一练:

#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <unistd.h>

int main(){
	pid_t pid, sid;

	printf("父进程pid : %d\n",getpid());

	pid = fork();
	if(pid == -1){
		perror("fork error");
		exit(0);
	}

	if(pid == 0){
		printf("子进程pid : %d\n",getpid());
		sid = setsid();
		printf("sid : %d\n",sid);
		sleep(10);
	}else{
		exit(0);
	}
	
	return 0;
}

实验结果:

[zhoumengkang@localhost unixStudy]$ make
gcc -Wall -g    create_daemon.c   -o create_daemon
[zhoumengkang@localhost unixStudy]$ ./create_daemon 
父进程pid : 6475
[zhoumengkang@localhost unixStudy]$ 子进程pid : 6476
sid : 6476

通过ps -ef|grep create_daemon发现该进程的tty?,所以已经变成了守护进程,这时候在终端ctrl + z无法终止该进程的运行。

[zhoumengkang@localhost ~]$ ps -ef|grep create_daemon
500       6476     1  0 22:51 ?        00:00:00 ./create_daemon
500       6478  6069  0 22:51 pts/1    00:00:00 grep create_daemon

从上面的实验中发现,setsid()返回值就是fork()出来的子进程的pid,这一结论在 man 手册非常详细的解释:

setsid() creates a new session if the calling process is not a process group leader.  The calling process is the leader of the new session, the process group  leader  of  the  new process  group,  and  has no controlling tty.  The process group ID and session ID of the calling process are set to the PID of the calling process.  The calling process  will  be the only process in this new process group and in this new session.

完整的代码

#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(){
	pid_t pid, sid;

	printf("父进程pid : %d\n",getpid());

	pid = fork();
	if(pid == -1){
		perror("fork error");
		exit(0);
	}

	if(pid == 0){
		printf("子进程pid : %d\n",getpid());
		sid = setsid();
		printf("sid : %d\n",sid);
	}else{
		exit(0);
	}

	chdir("/");

	for (int i = 0; i < 3; ++i){
		close(i);
	}
	// 把0号文件描述符指向/dev/null
	open("/dev/null",O_RDWR);
	// 把0号文件描述符赋值给空闲的文件描述符 1
	dup(0);
	// 把0号文件描述符赋值给空闲的文件描述符 2
	dup(0);


	while(1){
		sleep(1);
	}
	
	return 0;
}

题外话,正好今天讨论如何监控守护进程,我想的是通过一个 crontab 命令来检查进程的状态,代码演示

#!/bin/sh
restart=`nohup php /Users/zhoumengkang/Documents/html/2.php >> log.txt 2>&1 &`

findZombie=`ps aux|grep '[2].php'|awk '{if($8 == "Z"){printf "sudo kill -9 %d;%d;\"",$2,$restart}}'|sh`
$findZombie

if (($(ps -ef|grep '[2].php'|wc -l) < 1))
    then :
		$restart
fi


👇 下面是我的公众号,高质量的博文我会第一时间同步到公众号,给个关注吧!

评论列表