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;
}