守护进程

一、守护进程
        守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行任务或等待处理某些发生的事件。守护进程是一种很有用的进程。

Linux的大多数服务器就是守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任务。比如,作业规划进程crond等。

Linux系统启动时会启动许多系统服务器进程,这些系统服务进程没有控制终端,不能直接和用户交互。其他进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终

止,但系统服务进程不受用户登录注销的影响,他们一直运行着。这种进程有一个名称叫做守护进程(Daemon)。

        下面我们用ps axj命令查看系统中的进程。参数a表示不仅列出当前用户的进程,也列出所有其他用户的进程,参数x表述不仅列有控制终端的进程,也列出所有无控制终端的

进程,参数j表示列出与作业控制相关的信息。

    

         凡是TCGIP一栏写着-1的都是没有控制终端的进程,即守护进程。在COMMAND一列用括号括起来的名字表示内核线程,这些线程在内核里创建,没有用户空间代码。因 

此没有程序文件名和命令行,通常采用以K开头的名字,表示Kernel.init进程是第一个运行的进程,udevd负责维护/dev下的设备文件,acpid负责电源管理,syslog负责维

护/var/log下的日志文件,可以看出,守护进程常采用以d结尾的名字,表示Daemon。

二、创建守护进程:

创建一个守护进程大概分为六部:
1、调用umask将文件模式创建屏蔽字设置为0.

2、调用fork,父进程退出(eait)。原因:1)如果该进程作为一条简单的shell命令启动时,那么父进程终止使得shell认为该命令已经执行完毕。2)保证子进程不是一个进程组

的组长进程。

3、调用setsid创建一个回话。setsid会导致:1)调用进程成为新的会话的首进程。2)调用进程称为一个进程组的组长进程。3)调用进程没有控制终端。(再fork一次,保证daemon进程之后不会打开tty设备)

4、将当前工作目录改为根目录。

5、关闭不再需要的文件描述符。

6、其他:忽略SIGCHLD信号。

三、创建守护进程代码如下:

  1 #include<stdio.h>
  2 #include<signal.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 #include<fcntl.h>
  6 #include<sys/stat.h>
  7 void creat_daemon(void)
  8 {
  9     int i;
 10     int fd0;
 11     pid_t pid;
 12     struct sigaction sa;
 13     umask(0);
 14     if((pid=fork())<0)
 15     {}
 16     else if(pid!=0)
 17     {
 18         exit(0);
 19     }
 20     setsid();
 21     sigemptyset(&sa.sa_mask);
 22     sa.sa_flags=0;
 23     if(sigaction(SIGCHLD,&sa,NULL)<0)
 24     {
 25         return;
 26     }
 27     if((pid=fork())<0)
 28     {
 29         printf("fork error!\n");
 30         return;
 31     }
 32     else if(pid!=0)
 33     {
 34         exit(0);
 35     }
 36     if(chdir("/")<0)
 37     {
 38         printf("child dir error\n");
 39         return;
 40     }
 41     close(0);
 42     fd0=open("/dev/null",O_RDWR);
 43     dup2(fd0,1);
 44     dup2(fd0,2);
 45 }
 46 int main()
 47 {
 48     creat_daemon();
 49     while(1)
 50     {
 51         sleep(1);
 52     }
 53 }
四、为什么创建守护进程有人要fork两次
       创建守护进程最关键的一步是调用setsid函数创建一个新的会话(Session),并成为Session Leader。

       #include<unistd.h>
       pid_t setsid(void);
       该函数调用成功时返回新创建的Session的id(是当前进程的id),出错返回-1,注意,调用这个函数之前。当前进程不允许是这个进程组的Leader,否则该函数返回-1。要保 

证当前进程不是进程组的Leader也很容易,只要先fork再调用setsid就行了。fork创建的子进程和父进程在同一个进程组中,进程组的Leader必然是该组的第一个进程,所以子

进程不可能是该组进程的第一个进程,在子进程中调用setsid就不会有问题了。

成功调用该函数的结果是:

1、创建一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。

2、创建一个新的进程组,当前进程成为进程组的id,就是进程组的id。

3、如过当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,任然可以读写,但只是

一个普通打开文件而不是控制终端了。

         session中包含了很多东西,如:控制终端、进程组等等。如果我们只fork()一次,将第一个由父进程创建处的子进程分离就来作为守护进程,一般情况下也是没有问题

的。但是,如果此时通过什么方式让次进程创建出了一个与自己的Session相关的控制终端,那么则会产生一定的影响。所以,则有了第二次fork使子进程创建出了一个“孙子进

程”,并且我们还是使用第一个父进程创建出来的子进程进行setsid,但他并不是守护进程,该孙子进程进行进程相关的操作。简言之,因为子进程创建了一个新的Session,并

作为该Session的领头进程,同时这个Session包含了该孙子进程且他并不是领头进程。那么该孙子进程就永远无法创建出一个控制终端,也就没有任何影响。



发布了53 篇原创文章 · 获赞 3 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章