论文部分内容阅读
摘要:本文主要介绍了Linux的守护进程的概念,重点分析了守护进程的特性及如何创建守护进程,并给出了具体的实现实例。
关键词:守护进程 特性 创建守护进程
Linux系统启动时会启动很多系统服务进程,这些系统服务进程没有控制终端,不能直接和用户交互。其它进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但系统服务进程不受用户登录注销的影响,它们一直在运行着,这种进程就是守护进程(daemon)。例如著名的apache、telnet、ftp等服务程序都是守护进程。除了服务进程外,守护进程还可以配合shell编程,设计出适合用户自己的新功能,更好地维护系统,大大提高工作效率。比如,作业规划进程crond。下面来介绍一下守护进程的特性及如何创建守护进程。
1 守护进程的特性
1.1 所有的守护进程都是以超级用户启动的(UID为0),所以编写守护进程时要格外小心,编写不好的守护进程很可能对系统造成威胁。
1.2 没有一个守护进程具有控制终端,其终端名设置为问号(?),在后台运行。
1.3 守护进程不存在父进程,双亲的进程都为1,即init进程。
1.4 所有用户层守护进程都是进程组的组长进程以及会话的首进程,而且是这些进程组和会话中的唯一进程。
具有以上特征的进程就是守护进程,编写守护进程的关键实际上就是要满足守护进程的特性。
2 守护进程的编写步骤
2.1 让init进程成为新产生进程的父进程 程序运行后首先调用for函数创建子进程,并让父进程退出。这样,产生的子进程将变成孤儿进程,并被inti进程接管,同时,所产生的新进程将变为在后台运行。
2.2 调用setsid函数 通过调用setsid函数,使得新创建的进程脱离控制终端,同时创建新的进程组,并成为该进程组的首进程。这个步骤是创建守护最重要的一步,为了更好地理解这一步骤,下面介绍一下进程组、会话的基本概念。
在Linux系统中,每个进程都属于各自的进程组。进程组是一个或多个进程的集合。每个进程组都有类似于进程号的标识,称为进程组ID。进程组ID是由首进程的进程号决定的,每个进程组都存在一个首进程。
会话是一个或多个进程组的集合。与进程组类似,每个会话都存在一个首进程。
会话和进程组是Linux内核管理多用户情况下用户进程的方法。每个进程都属于一个进程组,而进程组又属于某个会话。当用户从终端登录系统,系统会创建一个新的会话。在该终端上启动的进程都会被系统划归到会话的进程组中。
会话中的进程是通过该会话中的首进程与终端相连的。该终端即是会话的控制终端。一个会话只能有一个控制终端。如果会话存在一个控制终端,则它必然拥有一个前台进程组。属于该组的进程可以从控制终端获得输入,而其他的进程组都为后台进程组。
由于守护进程没有控制终端,使用fork函数创建的子进程继承了父进程的控制终端、会话和进程组,因此,必须创建新的会话,以脱离父进程的影响。setsid函数就是用于创建新会话的。
setsid函数创建新会话,并使得调用setsid函数的进程成为新会话的首进程。调用setsid函数的进程是新创建会话中的惟一的进程组,进程组ID为调用进程的进程号,同时要求调用进程不为一个进程的首进程。由于在第一步中调用fork的父进程退出,使得子进程不可能是进程组的首进程。该会话的首进程没有控制终端与其相连。至此,满足了守护进程没有控制终端的要求。
2.3 改变当前目录为根目录 使用fork函数产生的子进程将继承父进程的工作目录,当进程没有结束时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。更改工作目录使用的函数是chdir。
2.4 重设文件权限掩码 文件权限掩码是用来屏蔽文件权限中的对应位的。由于使用fork函数新建的子进程继承了父进程的文件权限掩码,这会给子进程使用文件带来了很多麻烦。因此,把文件权限掩码设置为0,可以大大增强该守护进程的灵活性。设置文件权限掩码的函数是umask。
2.5 关闭文件描述符 进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。关闭它们的方法是:
for(i=0;i close(i);
3 守护进程实例
下面给出一个创建守护进程的实例,该守护进程实例包括两部分:主程序main.c和初始化程序init.c。主程序每隔10秒向目录/tmp中的日志daemon.log报告运行状态。初始化程序中的init_daemon函数负责生成守护进程。
3.1 初始化程序init.c
#include < unistd.h >
#include < signal.h >
#include < sys/param.h >
#include < sys/types.h >
#include < sys/stat.h >
#define MAXFILE 65535
void init_daemon(void)
{ int pid;
int i;
if(pid=fork())
exit(0);//创建子进程,结束父进程
else if(pid< 0)
exit(1);/创建子进程失败
setsid();//创建新会话,并担任该会话组的组长
chdir("/tmp");//改变工作目录到/tmp下
for(i=0;i< MAXFILE;i++)//关闭打开的文件描述符
close(i);
umask(0);//重设文件权限掩码
}
3.2 主程序main.c
#include < stdio.h >
#include < time.h >
void init_daemon(void);//守护进程初始化函数
main()
{ FILE *fp;
time_t t;
init_daemon();//初始化为daemon
while(1)//每隔10秒向daemon.log报告运行状态
{ sleep(10);//睡眠10秒
if((fp=fopen("daemon.log","a")) >=0)
{ t=time(0);
fprintf(fp," 守护进程还在运行,时间是:%s ",asctime(localtime(&t)) );
fclose(fp);
}
}
}
程序运行结果如图1:
运行该程序,它变成了一个守护进程,不再和当前终端关联。用ps命令看不到,必须带参数x才能看到。另外可以看到,用户关闭终端窗口或注销也不会影响守护进程的运行。
4 结束语
守护进程广泛应用于Linux/Unix环境下的系统管理、网络通信以及嵌入式应用等领域。本文分析了Linux守护进程的特性及如何创建守护进程,结合应用心得给出了程序实例,使其具有一定的实用性。
参考文献:
[1]张海.一种Linux操作系统守护进程的编程实现方法[J].广东水利电力职业技术学院学报,2006[2]:57-59.
[2]李玉波,朱自强,郭军.《Linux C编程》.清华大学出版社,2005.
[3]杜华.《Linux编程技术详解》.人民邮电出版社,2007.
[4]曹江华.《Linux最佳实践工具》.电子工业出版社,2009.
作者简介:王艳丽(1978-),女,讲师,硕士研究生。研究方向:软件工程,操作系统。
关键词:守护进程 特性 创建守护进程
Linux系统启动时会启动很多系统服务进程,这些系统服务进程没有控制终端,不能直接和用户交互。其它进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但系统服务进程不受用户登录注销的影响,它们一直在运行着,这种进程就是守护进程(daemon)。例如著名的apache、telnet、ftp等服务程序都是守护进程。除了服务进程外,守护进程还可以配合shell编程,设计出适合用户自己的新功能,更好地维护系统,大大提高工作效率。比如,作业规划进程crond。下面来介绍一下守护进程的特性及如何创建守护进程。
1 守护进程的特性
1.1 所有的守护进程都是以超级用户启动的(UID为0),所以编写守护进程时要格外小心,编写不好的守护进程很可能对系统造成威胁。
1.2 没有一个守护进程具有控制终端,其终端名设置为问号(?),在后台运行。
1.3 守护进程不存在父进程,双亲的进程都为1,即init进程。
1.4 所有用户层守护进程都是进程组的组长进程以及会话的首进程,而且是这些进程组和会话中的唯一进程。
具有以上特征的进程就是守护进程,编写守护进程的关键实际上就是要满足守护进程的特性。
2 守护进程的编写步骤
2.1 让init进程成为新产生进程的父进程 程序运行后首先调用for函数创建子进程,并让父进程退出。这样,产生的子进程将变成孤儿进程,并被inti进程接管,同时,所产生的新进程将变为在后台运行。
2.2 调用setsid函数 通过调用setsid函数,使得新创建的进程脱离控制终端,同时创建新的进程组,并成为该进程组的首进程。这个步骤是创建守护最重要的一步,为了更好地理解这一步骤,下面介绍一下进程组、会话的基本概念。
在Linux系统中,每个进程都属于各自的进程组。进程组是一个或多个进程的集合。每个进程组都有类似于进程号的标识,称为进程组ID。进程组ID是由首进程的进程号决定的,每个进程组都存在一个首进程。
会话是一个或多个进程组的集合。与进程组类似,每个会话都存在一个首进程。
会话和进程组是Linux内核管理多用户情况下用户进程的方法。每个进程都属于一个进程组,而进程组又属于某个会话。当用户从终端登录系统,系统会创建一个新的会话。在该终端上启动的进程都会被系统划归到会话的进程组中。
会话中的进程是通过该会话中的首进程与终端相连的。该终端即是会话的控制终端。一个会话只能有一个控制终端。如果会话存在一个控制终端,则它必然拥有一个前台进程组。属于该组的进程可以从控制终端获得输入,而其他的进程组都为后台进程组。
由于守护进程没有控制终端,使用fork函数创建的子进程继承了父进程的控制终端、会话和进程组,因此,必须创建新的会话,以脱离父进程的影响。setsid函数就是用于创建新会话的。
setsid函数创建新会话,并使得调用setsid函数的进程成为新会话的首进程。调用setsid函数的进程是新创建会话中的惟一的进程组,进程组ID为调用进程的进程号,同时要求调用进程不为一个进程的首进程。由于在第一步中调用fork的父进程退出,使得子进程不可能是进程组的首进程。该会话的首进程没有控制终端与其相连。至此,满足了守护进程没有控制终端的要求。
2.3 改变当前目录为根目录 使用fork函数产生的子进程将继承父进程的工作目录,当进程没有结束时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。更改工作目录使用的函数是chdir。
2.4 重设文件权限掩码 文件权限掩码是用来屏蔽文件权限中的对应位的。由于使用fork函数新建的子进程继承了父进程的文件权限掩码,这会给子进程使用文件带来了很多麻烦。因此,把文件权限掩码设置为0,可以大大增强该守护进程的灵活性。设置文件权限掩码的函数是umask。
2.5 关闭文件描述符 进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。关闭它们的方法是:
for(i=0;i
3 守护进程实例
下面给出一个创建守护进程的实例,该守护进程实例包括两部分:主程序main.c和初始化程序init.c。主程序每隔10秒向目录/tmp中的日志daemon.log报告运行状态。初始化程序中的init_daemon函数负责生成守护进程。
3.1 初始化程序init.c
#include < unistd.h >
#include < signal.h >
#include < sys/param.h >
#include < sys/types.h >
#include < sys/stat.h >
#define MAXFILE 65535
void init_daemon(void)
{ int pid;
int i;
if(pid=fork())
exit(0);//创建子进程,结束父进程
else if(pid< 0)
exit(1);/创建子进程失败
setsid();//创建新会话,并担任该会话组的组长
chdir("/tmp");//改变工作目录到/tmp下
for(i=0;i< MAXFILE;i++)//关闭打开的文件描述符
close(i);
umask(0);//重设文件权限掩码
}
3.2 主程序main.c
#include < stdio.h >
#include < time.h >
void init_daemon(void);//守护进程初始化函数
main()
{ FILE *fp;
time_t t;
init_daemon();//初始化为daemon
while(1)//每隔10秒向daemon.log报告运行状态
{ sleep(10);//睡眠10秒
if((fp=fopen("daemon.log","a")) >=0)
{ t=time(0);
fprintf(fp," 守护进程还在运行,时间是:%s ",asctime(localtime(&t)) );
fclose(fp);
}
}
}
程序运行结果如图1:
运行该程序,它变成了一个守护进程,不再和当前终端关联。用ps命令看不到,必须带参数x才能看到。另外可以看到,用户关闭终端窗口或注销也不会影响守护进程的运行。
4 结束语
守护进程广泛应用于Linux/Unix环境下的系统管理、网络通信以及嵌入式应用等领域。本文分析了Linux守护进程的特性及如何创建守护进程,结合应用心得给出了程序实例,使其具有一定的实用性。
参考文献:
[1]张海.一种Linux操作系统守护进程的编程实现方法[J].广东水利电力职业技术学院学报,2006[2]:57-59.
[2]李玉波,朱自强,郭军.《Linux C编程》.清华大学出版社,2005.
[3]杜华.《Linux编程技术详解》.人民邮电出版社,2007.
[4]曹江华.《Linux最佳实践工具》.电子工业出版社,2009.
作者简介:王艳丽(1978-),女,讲师,硕士研究生。研究方向:软件工程,操作系统。