while(!dead) learning++;
全部博文(132)
分类: LINUX
2013-04-01 10:23:24
Linux守护进程
linux服务器在启动时需要启动很多系统服务,他们向本地和网络用户提供了linux的系统功能接口,直接面向应用程序和用户。提供这些服务的程序是由运行在后台的守护进程来执行的。
守护进程是运行在后台,生存期长的一种特殊服务进程,他们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。他们常常在系统引导装入时启动,在系统关闭时终止。
由于在linux中,每一个系统终端与用户进行交流的界面称为终端,每一个从终端开始运行的进程都依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。但是守护进程却能够突破这种限制,它从被执行开始运转,直到整个系统关闭时才退出。如果想某个进程不因为用户,终端或其他进程的变化而受到影响,那么就必须把这个进程变成一个守护进程。
编写规则:
1:创建子进程,父进程退出
这是创建守护进程的第一步,由于守护进程是脱离控制终端的,因此,完成第一步后就会在shell终端造成一个程序已经运行完毕的现象。之后的所有工作都在子进程完成。
在linux中父进程先于子进程退出称为孤儿进程,而每当系统发现一个孤儿进程时,就会自动由1号进程(init)收养它,这样,原先的子进程就会变成init进程的子进程。
2:在子进程中创建新会话
在这里使用的是系统函数setsid,在具体介绍setsid之前,首先了解两个很重要的概念。
(1):进程组。它是一个或多个进程的集合。进程组由进程组ID来唯一标识。除了进程号(PID)之外,进程组ID也是一个进程的必备属性。每个进程组都有一个组长进程,其组长进程的进程号等于进程组ID。且该进程组ID不会因组长的退出而受到影响。
(2):会话周期。会话周期是一个或多个进程组的集合。通常,一个会话开始于用户登录,终止与用户退出,在此期间该用户运行的所有进程都属于这个会话期。
setsid函数:该函数用于创建一个新的会话,并担任该会话组的组长。调用setsid有下面的三个作用。
1:让进程摆脱原会话的控制
2:让进程摆脱原进程组的控制
3:让进程摆脱原控制终端的控制
那么,在创建守护进程时,为什么要调用setsid函数呢?呵呵~这个问题其实想想就会明白了
由于在我们创建守护进程的第一步调用了fork()函数来创建子进程,在将父进程退出。由于调用fork()函数时,子进程全盘复制了父进程的会话期,控制终端等,但会话期,进程组,控制终端等并没有改变,因此,这不是真正意义上的独立开来,而setsid函数能够使进程完全独立出来,从而摆脱其他进程的控制。
3:改变当前目录为根目录
使用fork创建的子进程继承了父进程的当前工作目录。由于在进程运行中,当前目录所在的文件系统(如:/mnt/usb)是不能卸载的。这对以后的使用会造成很多的麻烦,所以我们在使用u盘的时候尽量不要强制拔出,这样对u盘会有相当的损坏。因此通常的做法是让“/”作为守护进进程的当前工作目录,这样就可以避免上述的问题,当然,如果有什么特殊需要的话,也可以把当前目录切换到其他的路径。如/tmp。改变工作目录的常见函数是chdir
4:重置文件的权限掩码
首先要做的是调用umask将文件模式创建屏蔽字设为0。因为由继承得来的文件模式创建屏蔽字可能会拒绝设置某些权限
5:关闭文件描述符
同文件权限码一样,用fork函数新建的子进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读写,但他们一样消耗了系统资源,而且可能导致所在的文件系统无法挂载。所以那些文件描述符失去存在的价值,应该关闭。
6. 处理SIGCHLD信号
---- 处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将SIGCHLD信号的操作设为SIG_IGN。
---- signal(SIGCHLD,SIG_IGN);
---- 这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程。
三. 守护进程实例
//daemon.c
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXFILE 65535
volatile sig_atomic_t _running = 1;
void sigterm_handler(int arg);
int main()
{
pid_t pc;
int i,fd,len;
char *buf="this is a Dameon\n";
len = strlen(buf);
pc = fork(); //第一步
if(pc<0){
printf("error fork\n");
exit(1);
}
else if(pc>0)
exit(0);
setsid(); //第二步
chdir("/"); //第三步
umask(0); //第四步
for(i=0;i
close(i);
signal(SIGTERM, sigterm_handler);
if((fd=open("/tmp/dameon.log",O_CREAT|O_WRONLY|O_APPEND,0600))<0){
perror("open");
exit(1);
}
while( _running ){
write(fd,buf,len);
sleep(1); //1秒
}
close(fd);
}
void sigterm_handler(int arg)
{
_running = 0;
}
你可以查看/tmp/dameon.log,会一秒钟增加内容
下面是用linux的nohup命令来实现守护进程,
#!/bin/bash
#daemon.sh
while :
do
echo "this is a daemon" >> /tmp/daemon.log
sleep 1
done
执行: nohup ./daemon.sh &
和上面的效果是一样的!