看护进程(Daemon)是运转在后台的一种特别进程。它独立于操控终端而且周期性地履行某种使命或等候
处理某些发生的事情。看护进程是一种很有用的进程。
Linux的大多数服务器便是用看护进程完结的。比方,Internet服务器inetd,Web服务器httpd等。
一起,看护进程完结许多体系使命。比方,作业规划进程crond,打印进程lpd等。
看护进程的编程自身并不杂乱,杂乱的是各种版别的Unix的完结机制不尽相同,
形成不同 Unix环境下看护进程的编程规矩并不共同。
需求留意,照搬某些书上的规矩(特别是BSD4.3和低版别的System V)到Linux会呈现过错的。
下面结合一些长辈的文档和自己的比如说说看护进程的编程。
.基本概念
.进程
.每个进程都有一个父进程
.当子进程停止时,父进程会得到告诉并能获得子进程的退出状况。
.进程组
.每个进程也归于一个进程组
.每个进程主都有一个进程组号,该号等于该进程组组长的PID号
.一个进程只能为它自己或子进程设置进程组ID号
.会话期
.对话期(session)是一个或多个进程组的调集。
.setsid()函数能够树立一个对话期:
假如,调用setsid的进程不是一个进程组的组长,此函数创立一个新的会话期。
(1)此进程变成该对话期的首进程
(2)此进程变成一个新进程组的组长进程。
(3)此进程没有操控终端,假如在调用setsid前,该进程有操控终端,那么与该终端的联络被免除。
假如该进程是一个进程组的组长,此函数回来过错。
(4)为了确保这一点,咱们先调用fork()然后exit(),此刻只要子进程在运转,
子进程承继了父进程的进程组ID,可是进程PID却是新分配的,所以不或许是新会话的进程组的PID。
然后确保了这一点。
if((pid=fork())>0) //parent
exit(0);
else if(pid==0){ //th1 child
setsid(); //th1是成为会话期组长
if(fork() ==0){ //th2不会是会话期组长(变成孤儿进程组)
…
}
}
一. 看护进程及其特性
(1)看护进程最重要的特性是后台运转。在这一点上DOS下的常驻内存程序TSR与之类似。
(2)其次,看护进程有必要与其运转前的环境阻隔开来。这些环境包括未封闭的文件描述符,操控终端,
会话和进程组,作业目录以及文件创立掩模等。这些环境通常是看护进程从履行它的父进程(特别是shell)
中承继下来的。
(3)最终,看护进程的发动办法有其特别之处。它能够在Linux体系发动时从发动脚本/etc/rc.d中发动,
能够由作业规划进程crond发动,还能够由用户终端(通常是 shell)履行。
总归,除开这些特别性以外,看护进程与一般进程基本上没有什么差异。
因而,编写看护进程实际上是把一个一般进程依照上述的看护进程的特性改形成为看护进程。
二. 看护进程的编程关键 (来自UEAP)
前面讲过,不同Unix环境下看护进程的编程规矩并不共同。所幸的是看护进程的编程准则其实都相同,
差异在于详细的完结细节不同。这个准则便是要满意看护进程的特性。
一起,Linux是根据Syetem V的SVR4并遵从Posix规范,完结起来与BSD4比较更便利。编程关键如下;
1. 在后台运转。
为避免挂起操控终端将Daemon放入后台履行。办法是在进程中调用fork使父进程停止,
让Daemon在子进程中后台履行。
if(pid=fork())
exit(0); //是父进程,完毕父进程,子进程持续
2. 脱离操控终端,登录会话和进程组
进程归于一个进程组,进程组号(GID)便是进程组长的进程号(PID)。登录会话能够包括多个进程组。
这些进程组同享一个操控终端。这个操控终端通常是创立进程的登录终端。
操控终端,登录会话和进程组通常是从父进程承继下来的。
咱们的意图便是要脱节它们,使之不受它们的影响。
办法是在第1点的基础上,调用setsid()使进程成为会话组长:
setsid();
阐明:当进程是会话组长时setsid()调用失利。但第一点现已确保进程不是会话组长。
setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与本来的登录会话和进程组脱离。
因为会话进程对操控终端的独占性,进程一起与操控终端脱离。
3. 制止进程从头翻开操控终端
现在,进程现已成为无终端的会话组长。但它能够从头恳求翻开一个操控终端。
能够经过使进程不再成为会话组长来制止进程从头翻开操控终端:
if(pid=fork())
exit(0); //完毕第一子进程,第二子进程持续(第二子进程不再是会话组长)
4. 封闭翻开的文件描述符
进程从创立它的父进程那里承继了翻开的文件描述符。如不封闭,将会糟蹋体系资源,
形成进程地点的文件体系无法卸下以及引起无法意料的过错。按如下办法封闭它们:
for(i=0;i 封闭翻开的文件描述符close(i);>
5. 改动当前作业目录
进程活动时,其作业目录地点的文件体系不能卸下。一般需求将作业目录改动到根目录。
关于需求转储中心,写运转日志的进程将作业目录改动到特定目录如 /tmpchdir(/)
6. 重设文件创立掩模
进程从创立它的父进程那里承继了文件创立掩模。它或许修正看护进程所创立的文件的存取位。
为避免这一点,将文件创立掩模铲除:umask(0);
7. 处理SIGCHLD信号
处理SIGCHLD信号并不是有必要的。
但关于某些进程,特别是服务器进程往往在恳求到来时生成子进程处理恳求。
假如父进程不等候子进程完毕,子进程将成为僵尸进程(zombie)然后占用体系资源。
假如父进程等候子进程完毕,将添加父进程的担负,影响服务器进程的并发功能。
在Linux下能够简略地将 SIGCHLD信号的操作设为SIG_IGN。
signal(SIGCHLD,SIG_IGN);
这样,内核在子进程完毕时不会发生僵尸进程。