启动Linux系统时往往需要启动很多系统服务程序,这些系统服务程序是运行在后台的,不受用户登录注销的影响,它们一直在运行着,这些服务程序被称为守护进程(daemon)。由于守护进程运行在后台中,不可能向终端输出相关的运行信息,因此,日志系统是守护进程用于记录信息的重要手段。Linux的大多数服务器就是用守护进程的方式实现的。
图9-8所示为用“psaxj”命令查看系统中进程的结果。参数a表示不仅列有当前用户的进程,也列出所有其他用户的进程;参数x表示不仅列有控制终端的进程,也列出所有无控制终端的进程;参数j表示列出与作业控制相关的信息。
图9-8 用“psaxj”命令查看系统中进程的结果
凡是TPGID栏写着-1的都是没有控制终端的进程,也就是守护进程。在Linux系统中,要编程实现一个守护进程必须遵守如下步骤。
1)调用fork()函数创建子进程后,使父进程立即退出。这样,产生的子进程将变成孤儿进程,同时,所产生的新进程将在后台运行。
2)调用setsid()函数,使得新创建的进程脱离控制终端,同时创建新的进程组,并成为该进程组的首进程。由于守护进程没有控制终端,而使用fork()函数创建的子进程继承了父进程的控制终端、会话和进程组,因此,必须创建新的会话,以脱离父进程的影响。Linux系统提供了setsid()函数用于创建新的会话。setsid()函数的原型如下所示。
函数调用成功返回进程的会话ID,若失败,则返回-1。
setsid()函数将创建新的会话,并使得调用setsid()函数的进程成为新会话的领头进程。调用setsid()函数的进程是新创建会话中的唯一的进程组。进程组ID为调用进程的进程号。setsid()函数产生这一结果还有个条件,即调用进程不为一个进程的领头进程。由于在第一步中调用fork()的父进程退出,使得子进程不可能是进程组的领头进程。该会话的领头进程没有控制终端与其相连。至此,满足了守护进程没有控制终端的要求。
3)使用fork()函数产生的子进程将继承父进程的当前工作目录。当进程没有结束时,其工作目录是不能被卸载的。为了防止这种问题发生,守护进程一般会将其工作目录更改到根目录下(/目录)。
4)关闭文件描述符,并重定向标准输入、输出和错误输出。新产生的进程从父进程继承了某些打开的文件描述符。如果不使用这些文件描述符,则需要关闭它们。守护进程是运行在系统后台的,不应该在终端有任何输出信息。可以使用dup()函数将标准输入、输出和错误输出重定向到/dev/null设备上。
5)将文件创建时使用的屏蔽字设置为0。很多情况下,守护进程会创建一些临时文件。出于安全性的考虑,往往不希望这些文件被别的用户查看。可以使用umask(0)将屏蔽字清零。
调用setsid()函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。若要保证当前进程不是进程组的Leader,则先调用fork(),再调用setsid()。用fork()创建的子进程和父进程在同一个进程组中,进程组的Leader必然是该组的第一个进程。所以,子进程不可能是该组的第一个进程,在子进程中调用setsid()就不会有问题了。(www.xing528.com)
【例9-3】创建守护进程。
要求创建守护进程。
设计步骤
1)在Vim中创建一个新工程文件,命名为“example9_3.c”和“example9_4.c”。
2)在“example9_3.c”和“example9_4.c”中创建的代码如下所示。
3)用GCC编译运行程序,结果如图9-9所示。
图9-9 例9-3的运行结果
从输出可以发现守护进程的各种特性都满足要求。
Linux的大多数服务器就是用守护进程的方式实现的,如Internet服务器进程inetd,Web服务器进程http等。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。