简述Linux下的守护进程

  我记得,第一次将阿里云拿到手时,第一件事就是给它安装了一个unbutu14版本,第二件事就是对它进行update更新.

  在输入apt-get update后,看到它开始更新软件列表时,我就想:诶?要是这个时候,我关闭掉ssh窗口,它更新还会不会运行?

  略做思考,觉得这命令是运行在linux服务器上的,只要服务器不关,它应该会自动更新.....后来没做验证,这件事也就这么过去了!

  直到前几周,看到ngnix模块开发教程时,发现ngnix是一个多进程服务器,它有一个master进程来管理其他worker进程.而worker进程以守护进程启动.

  于是便百度了一波守护进程,对守护进程简单的了解了一下....今天在此,对守护进程进行简单的总结.

一、概念

  守护进程,又称精灵进程.其最大的特点在于:不受用户注销登录的影响,只要linux开着机,它就在运行.

  知道了守护进程是什么,那么我们要写一个守护进程的程序,怎么做?

二、如何创建守护进程?

  我们要想创建一个守护进程,很简单,需要用到下面的函数:

#include<unistd.h>
int daemon(int nochdir,int noclose);

  nochdir:是否改变主工作目录.如果为1,表示不改变主工作目录.如果为0,表示将主工作目录修改为根目录/.

  noclose:是否关闭没有必要的文件描述符.如果为1,表示不关闭0、1、2;如果为0,则会将0、1、2等文件描述符重定向到信息黑洞中(/dev/null).

  成功返回0,失败返回-1;

  下面是成功创建一个守护进程,向其它终端打印消息的例子:

////////////////////////////////////
//文件说明:test.c
//作者:高小调
//创建时间:2017年06月27日 星期二 20时08分29秒
//开发环境:Kali Linux/g++ v6.3.0
////////////////////////////////////
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(){
	daemon(0,0);  //创建守护进程
	//打开其他终端的设备文件
	int fd = open("/dev/pts/2",O_WRONLY);
	if(fd == -1){
		return -1;
	}
	char str[]="Hello World!\n";
	while(1){
		//不断向其他终端发送Hello World!
		write(fd,str,sizeof(str));
		sleep(1);
	}
	return 0;
}

  可能有人会问:向终端打印消息用printf函数不就行了?何必搞得那么累!

  注意:守护进程与其他环境是隔离开的(进程组、终端、会话).并且,其文件描述符0、1、2已经被重定向到了/dev/null中,所以此时你直接通过printf函数打印的东西就会被当作垃圾处理掉了.

  因此为了演示效果,我创建了三个终端,我让守护进程不断在第三个终端中的输出队列中写东西.(当然你也可以打开文件,但如果你想看到写进去东西的话,得做保存处理)

三、守护进程特点

  通过以上代码,我们可以创建一个守护进程,那么本小结来对守护进程的特点做一总结:

  1.守护进程不受用户登录、注销影响,只要运行起来,只要linux不关机、自己不主动退出、不受到乱七八糟的信号,它便一直运行.为什么?(因为它自成一个会话,因此不会受其他会话影响)

  2.守护进程没有终端.(这就解释了,为什么用printf不能向终端输出消息).

四、模拟实现守护进程

  哇,守护进程居然这么吊!那我不通过daemon函数,可以自己实现不?

  当然可以!!!以下便是自己创建守护进程的代码,步骤详见注释:

void myDaemon(){
	umask(0);			//1.将umask设置为0,方便解决守护进程创建文件的权限问题
	chdir("/");			//2.改变进程主工作目录
	if(fork() > 0){		//3.fork子进程,父进程退出(进程组组长不能运行setid函数)
		exit(0);
	}
	setsid();			//4.在子进程中新建会话!
	close(0);			//5.关闭不必要的文件描述符
	close(1);
	close(2);
}

 五、完整代码及测试

////////////////////////////////////
//文件说明:守护进程相关代码
//作者:高小调
//创建时间:2017年06月27日 星期二 20时08分29秒
//开发环境:Kali Linux/g++ v6.3.0
////////////////////////////////////

#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
void myDaemon(){
	umask(0);			//1.将umask设置为0,方便解决守护进程创建文件的权限问题
	chdir("/");			//2.改变进程主工作目录
	if(fork() > 0){		//3.fork子进程,父进程退出(进程组组长不能运行setid函数)
		exit(0);
	}
	setsid();			//4.在子进程中新建会话!
	close(0);			//5.关闭不必要的文件描述符
	close(1);
	close(2);
}
int main(){
        //运行时,至少打开3个终端
	myDaemon();
	//打开其他终端的设备文件
	int fd = open("/dev/pts/2",O_WRONLY);
	if(fd == -1){
		return -1;
	}
	char str[]="Hello World!\n";
	while(1){
		//不断向其他终端发送Hello World!
		write(fd,str,sizeof(str));
		sleep(1);
	}
	return 0;
}
posted @ 2017-06-27 20:44  Linux专题站  阅读(446)  评论(0编辑  收藏  举报