Linux:守护进程解析、如何实现守护进程

来源:互联网 发布:淘宝达人申请直播入口 编辑:程序博客网 时间:2024/06/07 02:03

1、守护进程:

守护进程也称精灵进程(Daemon),是运行在后台的⼀一种特殊进程。它独立于控制终端周期性地执行某种任务或等待处理某些发生的事件。守护进程是⼀一种很有用的进程。Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任

 

务。比如,作业规划进程crond等。Linux系统启动时会启动很多系统服务进程,

 

这些系统服务进程没有控制终端,不能直接和用户交互。其它进程都是在用户

 

登录或运行程序时创建,在运行结束或用户注销时终止,但系统服务进程不受用户登录注销的影响,它们一直在运行着。这种进程有⼀一个名称叫守护进程(Daemon)。

 

 

2、查看系统中的守护进程:

 

用ps axj命令查看系统中的进程(参数a表示不仅列当前用户的进程,也列

 

出所有其他用户的进程,参数x表示不仅列有控制终端的进程,也列出所有无控

 

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

 

凡是TPGID一栏写着-1的都是没有控制终端的进程,也就是守护进程。在

 

COMMAND一列用[] 括起来的 名字表示内核线程,这些线程在内核里创建,没

 

有用户空间代码,因此没有程序文件名和命令行, 通常采用以k开头的名字,表

 

示Kernel。init进程我们已经很熟悉了,udevd负责维护/dev目录下的 设备文

 

件,acpid负责电源管理,syslogd负责维护/var/log下的日志文件,可以看出,守护

 

进程通 常采用以d结尾的名字,表示Daemon。

 

 

3、自己实现守护进程:

(1)、调用umask将文件模式创建屏蔽字设置为0.

文件权限掩码是指屏蔽掉文件权限中的对应位,比如一个文件权限掩码是050它就屏蔽了文件拥有者得可读与可写权限,fork()创建的子进程会继承父进程的文件权限掩码,所以我们把文件权限掩码设为0,可以增加子进程的灵活性,使用umask(0) 即可。

(2)、调用fork,父进程退出(exit)。

原因:

1)如果该守护进程是作为一条简单的shell命令启动的,那么父进程终止使得shell认为该命令已经执行完毕。

2)保证子进程不是一个进程组的组长进程。

 

守护进程需要脱离shell终端,造成一种程序关闭的假象,所有的工作都在子进程中完成,创建子进程,父进程退出,会造成子进程成为一个孤儿进程,在linux中当系统发现一个孤儿进程,就会1号进程(init进程)收养它,这样子进程就变成init子进程了。代码如下:

                                  if(fork() > 0)

                                  {

                                         exit(0);

                                      }

(3)、 调用setsid创建一个新会话。setsid会导致:

1)调用进程成为新会话的首进程。

2)调用进程成为一个进程组的组长进程 。

3)调用进程没有控制终端。(再次fork一次,保证daemon进程,之后不会打开tty设备)。

  NAME

       setsid -creates a session and sets the process group ID

 

SYNOPSIS

       #include<unistd.h>

 

       pid_tsetsid(void);

 

DESCRIPTION

      setsid()  creates a new session ifthe calling process is not a process

       groupleader.  The calling process is theleader of  the  new session,

       the  process group leader of the new processgroup, and has no control-

       lingtty.  The process group ID and session IDof the  calling  process

       are setto the PID of the calling process.  Thecalling process will be

       the onlyprocess in this new process group and in this new session.

 

RETURN VALUE

       Onsuccess, the (new) session ID of the calling process  is  returned.

       On  error, (pid_t) -1  is  returned, and errno is set to indicate the

       error.

 

           该函数调用成功时返回新创建的Session的id(其实也就是当前进程的id),

    出错返回-1。注意,调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证当前进程不是进 程组的Leader也很容易,只要先fork再调用setsid就行了。fork创建的子进程和父进程在同一个进 程组中,进程组的Leader必然是该组的第⼀一个进程,所以子进程不可能是该组的第一个进程,在子进程中调用setsid就不会有问题了。成功调用该函数的结果是:

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

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

3. 如果当前进程原本有⼀一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是一个普通的打开文件而不是控制终端了。

 

(4)、禁止进程重新打开控制终端:
  现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:
 
if(pid=fork())
     exit(0); //结束第一子进程,第二子进程继续(第二子进程不再是会话组长)

 

(5)、将当前工作目录更改为根目录。

 

NAME

       setsid - creates a session and sets theprocess group ID

 

SYNOPSIS

       #include <unistd.h>

 

       pid_t setsid(void);

 

DESCRIPTION

       setsid() creates a new session if the calling process is not a process

       group leader.  The calling process is the leader of  the new  session,

       the process group leader of the new process group, and has no control-

       ling tty.  The process group ID and session ID ofthe  calling  process

       are set to the PID of the callingprocess.  The calling process will be

       the only process in this new processgroup and in this new session.

 

RETURN VALUE

       On success, the (new) session ID of thecalling  process  is returned.

       On error,  (pid_t) -1  is returned,  and errno is set toindicate the

       error.

 

(6)、关闭不再需要的文件描述符。

 

             进程从父进程中继承了一些打开的文件描述符,不再需要使用时及时关闭,否则将会引起无法预料的错误和资源浪费。

      Close(0);

      Close(1);

      Close(2);

      即标准输入、输出、错误。

 

(7)、其他:忽略SIGCHLD信号。

                  处理SIGCHLD信号并不是必须的。 但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。

    如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下可以简单地将 SIGCHLD信号的操作设为SIG_IGN。

 

signal(SIGCHLD,SIG_IGN);

 

   这样,内核在子进程结束时不会产生僵尸进程。

    这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程。

 

 

 

守护进程的完整代码:

 

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

#include <sys/stat.h>

 

void create_daemon()

{

   pid_tpid;

   umask(0);//设置文件掩码

 

   if(pid= fork() > 0)//调用fork()函数,父进程退出

   {

          exit(0);

   }

   setsid();//设置新会话

   signal(SIGCHLD,SIG_IGN);//处理SIGCHLD信号

 

   if(pid= fork() < 0)// 禁止进程重新打开控制终端

   {

          printf("forkerror");

          return;

   }

   elseif(pid != 0)

   {

          exit(0);

   }

 

   chdir("/");//改变当前工作目录

 

   close(0);//关闭打开的不再需要的文件描述符

   close(1);

   close(2);

 

}

 

int main()

{

   create_daemon();

   while(1)

   {

          sleep(1);

   }

 

   return0;

}

 

 

测试:

 

0 0
原创粉丝点击