Linux编程---守护进程

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
必须显式等待子进程结束才能释放僵尸进程。 


三. 守护进程实例 

---- 
守护进程实例包括两部分:主程序test.c和初始化程序init.c。主程序每隔
一分钟向/tmp目录中的日志test.log报告运行状态。初始化程序中的init_daemo
n
函数负责生成守护进程。读者可以利用init_daemon函数生成自己的守护进程。


#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/param.h>
void init_daemon(void)
{
 int pid;
 int i;
 if(pid=fork())
 exit(0);                                            //是父进程,结束父进程
 else if(pid<0)                                 //若进程的PID号小于0,则说名子进程创建失败 
 exit(1);                                          //退出
//上面为结束父进程,隔离子进程在后台执行
 setsid();                                        //第一个子进程称为新的会话组长和进程组长并控制 终端分离
 if(pid=fork())
 exit(0);                                        //是第一个子进程,结束第一个子进程
 else if(pid<0)                             //fork失败,退出
 exit(1);                                        //这就是创建第二个的子进程,继续执行
 for(i=0;i<NOFILE;i)                   //关闭打开的文档描述符
 close(i);
 chdir("/tmp");                           //改变工作目录到/tmp
 umask(0);                                 //重设文档权限掩码  
 return;
}


test.c

#include<stdio.h>
#include<time.h>
void init_daemon(void);                      //守护进程初始化函数
main()
{
 FILE *fp;                                            //fp为指向FILE的指针,里面存放着FILE的地址
 time_t t;
 init_daemon();                                 //初始化守护进程
while(1)                                              //每隔一分钟向test.log报告运行状态
{
 sleep(60);                                           //睡眠一分钟
 if((fp=fopen("test.log","a"))>=0)   
{
  t=time(0);
  fprintf(fp,"I'm here at %s\n",asctime(localtime(&t)));
fclose(fp);
}
 }
}

xiongyao@xiongyao-Lenovo:~/c编程$ gcc -g -o  test  init.c test.c


xiongyao@xiongyao-Lenovo:~/c编程$ ./test


编译通过:通过命令可以查看守护进程


ps  -ef


xiongyao  2755     1 99 08:07 ?        00:06:03 ./test
xiongyao  2786     1 99 08:09 ?        00:04:37 ./test
root      2813     2  0 08:11 ?        00:00:00 [kworker/1:0]
xiongyao  2891     1  2 08:12 ?        00:00:01 /usr/bin/python /usr/share/oneco
lp        2983   899  0 08:12 ?        00:00:00 /usr/lib/cups/notifier/dbus dbus
xiongyao  3077  2247  0 08:13 pts/2    00:00:00 ps -ef


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值