守护进程特征:
- 没有控制终端
- 经常在系统引导启动时启动,仅在系统关闭时终止
- 守护进程的父进程是1号进程,在ubuntu 14.4上面用户守护进程的父进程不一定是1号进程,系统给用户空间分配了一个类似于1号进程的init–>user进程,进程号不一定
编写守护进程
方式一:
首先调用
umask
将文件模式创建屏蔽字设置为一个已知值(通常是0)因为继承而来的文件模式创建屏蔽字很可能会被设置为拒绝某些权限。如果守护进程要创建文件,那么它可能需要设置特定的权限。
然后调用
fork
,然后使父进程exit
。这样做实现了下面几点:如果该守护进程是作为一条简单
shell
命令启动的,那么父进程终止会让shell
认为这条命令已经执行完毕,不占用终端。子进程继承了父进程的进程组
ID
,获得了一个新的进程ID
,这就保证了子进程不是一个进程组的组长ID
,这就是后面的setsid
调用的先决条件
然后调用
setsid
创建一个新会话。执行完setsid
之后,调用进程将成为:新会话的首进程,
是一个新进程组的组长进程,
同时没有控制终端
将当前工作目录改为根目录
/
这是因为守护进程要求在系统重启/关闭之前是一直存在的。所以如果守护进程的当前工作目录在一个挂载的文件系统中,则该文件系统就不能被卸载。而从父进程中继承过来的当前工作目录可能就在一个挂在的文件系统中。
- 当然某些守护进程可能会将当前工作目录更改到某个指定位置(不一定是
/
)
- 当然某些守护进程可能会将当前工作目录更改到某个指定位置(不一定是
关闭不再需要的文件描述符。这使得守护进程不再持有从其父进程继承而来的任何文件描述符。
可以先判断最高文件描述符值,然后关闭直到该值的所有描述符
使用
getrlimit
获得进程能够打开的最大文件数。
某些守护进程打开
/dev/null/
使其具有文件描述符0,1,2
。这样任何试图读标准输入、写标准输出、写标准错误的库例程都不会产生任何效果。因为守护进程并不与任何终端关联,所以其输出无处显示,也无法获得用户的输入。
处理一些特殊的信号:
SIGHUP,SIGTTIN,SIGTTOU,SIGCHLD,SIGTSTP
守护进程一文中:
但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源(关于僵尸进程的更多详情,请看《僵尸进程》)。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在 Linux 下可以简单地将 SIGCHLD 信号的操作设为 SIG_IGN 。关于信号的更详细用法,请看《信号中断处理》。
注:通过忽略信号SIGCHLD,不关心子进程在结束的时候发出的信号,交由内核处理,不会产生僵死进程。
//只fork了一次
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
int main(){
pid_t pid;
struct rlimit r;
umask(0);
if((pid = fork()) < 0