分享
 
 
 

编写Linux/Unix守护进程

王朝system·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

守护进程在Linux/Unix系统中有着广泛的应用。有时,开发人员也想把自己的程序变成守护进程。在创建一个守护进程的时候,要接触到子进程、进程组、会晤期、信号机制、文件、目录和控制终端等多个概念。因此守护进程还是比较复杂的,在这里详细地讨论Linux/Unix的守护进程的编写,总结出八条经验,并给出应用范例。

编程要点

1.屏蔽一些有关控制终端操作的信号。防止在守护进程没有正常运转起来时,控制终端受到干扰退出或挂起。示例如下:

signal(SIGTTOU,SIG_IGN);

signal(SIGTTIN,SIG_IGN);

signal(SIGTSTP,SIG_IGN);

signal(SIGHUP ,SIG_IGN);

所有的信号都有自己的名字。这些名字都以“SIG”开头,只是后面有所不同。开发人员可以通过这些名字了解到系统中发生了什么事。当信号出现时,开发人员可以要求系统进行以下三种操作:

◆ 忽略信号。大多数信号都是采取这种方式进行处理的,这里就采用了这种用法。但值得注意的是对SIGKILL和SIGSTOP信号不能做忽略处理。

◆ 捕捉信号。最常见的情况就是,如果捕捉到SIGCHID信号,则表示子进程已经终止。然后可在此信号的捕捉函数中调用waitpid()函数取得该子进程的进程ID和它的终止状态。另外,如果进程创建了临时文件,那么就要为进程终止信号SIGTERM编写一个信号捕捉函数来清除这些临时文件。

◆ 执行系统的默认动作。对绝大多数信号而言,系统的默认动作都是终止该进程。

对这些有关终端的信号,一般采用忽略处理,从而保障了终端免受干扰。

这类信号分别是,SIGTTOU(表示后台进程写控制终端)、SIGTTIN(表示后台进程读控制终端)、SIGTSTP(表示终端挂起)和SIGHUP(进程组长退出时向所有会议成员发出的)。

2.将程序进入后台执行。由于守护进程最终脱离控制终端,到后台去运行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。这就是常说的“脱壳”。子进程继续函数fork()的定义如下:

#include

#include

pid_t fork(void);

该函数是Linux/Unix编程中非常重要的函数。它被调用一次,但返回两次。这两次返回的区别是子进程的返回值为“0”,而父进程的返回值为子进程的ID。如果出错则返回“-1”。

3.脱离控制终端、登录会话和进程组。开发人员如果要摆脱它们,不受它们的影响,一般使用 setsid() 设置新会话的领头进程,并与原来的登录会话和进程组脱离。这只是其中的一种方法,也有如下处理的办法:

if

((fd = open("/dev/tty",O_RDWR)) = 0) {

ioctl(fd,TIOCNOTTY,NULL);

close(fd);

}

其中/dev/tty是一个流设备,也是终端映射,调用close()函数将终端关闭。

4.禁止进程重新打开控制终端。进程已经成为无终端的会话组长,但它可以重新申请打开一个控制终端。开发人员可以通过不再让进程成为会话组长的方式来禁止进程重新打开控制终端,需要再次调用fork函数。

上面的程序代码表示结束第一子进程,第二子进程继续(第二子进程不再是会话组长)。

5. 关闭打开的文件描述符,并重定向标准输入、标准输出和标准错误输出的文件描述符。进程从创建它的父进程那里继承了打开的文件描述符。如果不关闭,将会浪费系统资源,引起无法预料的错误。关闭三者的代码如下:

for (fd = 0, fdtablesize = getdtablesize();

fd

close(fd);

但标准输入、标准输出和标准错误输出的重定向是可选的。也许有的程序想保留标准输入(0)、标准输出(1)和标准错误输出(2),那么循环应绕过这三者。代码如下:

for (fd =3, fdtablesize = getdtablesize();

fd

close(fd);

有的程序有些特殊的需求,还需要将这三者重新定向。示例如下:

error=open("/tmp/error",O_WRONLY|O_CREAT,

0600);

dup2(error,2);

close(error);

in=open("/tmp/in",O_RDONLY|O_CREAT,0600);

if(dup2(in,0)==-1)

perror("in");

close(in);

out=open("/tmp/out",O_WRONLY|O_CREAT,0600);

if(dup2(out,1)==-1) perror("out");

close(out);

6.改变工作目录到根目录或特定目录进程活动时,其工作目录所在的文件系统不能卸下。

一般需要将工作目录改变到根目录或特定目录,注意用户对此目录需要有读写权。防止超级用户卸载设备时系统报告设备忙。

7.处理SIGCHLD信号。SIGCHLD信号是子进程结束时,向内核发送的信号。

如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。因此需要对SIGCHLD信号做出处理,回收僵尸进程的资源,避免造成不必要的资源浪费。可以用如下语句:

signal(SIGCHLD,(void *)reap_status);

捕捉信号SIGCHLD,用下面的函数进行处理:

void reap_status()

{ int pid;

union wait status;

while ((pid = wait3(&status,WNOHANG,NULL)) 0)

…… }

8.在Linux/Unix下有个syslogd的守护进程,向用户提供了syslog()系统调用。任何程序都可以通过syslog记录事件。

由于syslog非常好用和易配置,所以很多程序都使用syslog来发送它们的记录信息。一般守护进程也使用syslog向系统输出信息。syslog有三个函数,一般只需要用syslog(...)函数,openlog()/closelog()可有可无。syslog()在shslog.h定义如下:

#include

void syslog(int priority,char *format,...);

其中参数priority指明了进程要写入信息的等级和用途。第二个参数是一个格式串,指定了记录输出的格式。在这个串的最后需要指定一个%m,对应errno错误码。

应用范例

下面给出Linux下编程的守护进程的应用范例,在UNIX中,不同版本实现的细节可能不一致,但其实现的原则是与Linux一致的。

#include

#include

#include

main(int argc,char **argv)

{

time_t now;

int childpid,fd,fdtablesize;

int error,in,out;

/* 忽略终端 I/O信号,STOP信号 */

signal(SIGTTOU,SIG_IGN);

signal(SIGTTIN,SIG_IGN);

signal(SIGTSTP,SIG_IGN);

signal(SIGHUP ,SIG_IGN);

/* 父进程退出,程序进入后台运行 */

if(fork()!=0) exit(1);

if(setsid()

/* 子进程退出,孙进程没有控制终端了 */

if(fork()!=0) exit(1);

if(chdir("/tmp")==-1)exit(1);

/* 关闭打开的文件描述符,包括标准输入、标准输出和标准错误输出 */

for (fd = 0, fdtablesize = getdtablesize(); fd

close(fd);

umask(0);/*重设文件创建掩模 */

signal(SIGCHLD,SIG_IGN);/* 忽略SIGCHLD信号 */

/*打开log系统*/

syslog(LOG_USER|LOG_INFO,"守护进程测试!\n");

while(1)

{

time(&now);

syslog(LOG_USER|LOG_INFO,"当前时间:\t%s\t\t\n",ctime(&now));

sleep(6);

}

}

此程序在Turbo Linux 4.0下编译通过。这个程序比较简单,但基本体现了守护进程的编程要点。读者针对实际应用中不同的需要,还可以做相应的调整。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有