首页 > 代码库 > Linux守护进程简介和实例详解

Linux守护进程简介和实例详解

Linux守护进程简介和实例详解

简介

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

下面是linux系统中常见的一些守护进程.

amd:自动安装NFS(网络文件系统)守侯进程
apmd:高级电源管理 
Arpwatch:记录日志并构建一个在LAN接口上看到的以太网地址和IP地址对数据库 
Autofs:自动安装管理进程automount,与NFS相关,依赖于NIS 
Bootparamd:引导参数服务器,为LAN上的无盘工作站提供引导所需的相关信息 
crond:Linux下的计划任务 
Dhcpd:启动一个DHCP(动态IP地址分配)服务器 
Gated:网关路由守候进程,使用动态的OSPF路由选择协议 
Httpd:WEB服务器 
Inetd:支持多种网络服务的核心守候程序 
Innd:Usenet新闻服务器 
Linuxconf:允许使用本地WEB服务器作为用户接口来配置机器 
Lpd:打印服务器 
Mars-nwe:mars-nwe文件和用于Novell的打印服务器 
Mcserv:Midnight命令文件服务器 
named:DNS服务器 
netfs:安装NFS、Samba和NetWare网络文件系统 
network:激活已配置网络接口的脚本程序 
nfs:打开NFS服务 
nscd:nscd(Name Switch Cache daemon)服务器,用于NIS的一个支持服务,它高速缓存用户口令和组成成员关系 
portmap:RPC portmap管理器,与inetd类似,它管理基于RPC服务的连接 
postgresql:一种SQL数据库服务器 
routed:路由守候进程,使用动态RIP路由选择协议 
rstatd:一个为LAN上的其它机器收集和提供系统信息的守候程序 
ruserd:远程用户定位服务,这是一个基于RPC的服务,它提供关于当前记录到LAN上一个机器日志中的用户信息 
rwalld:激活rpc.rwall服务进程,这是一项基于RPC的服务,允许用户给每个注册到LAN机器上的其他终端写消息 
rwhod:激活rwhod服务进程,它支持LAN的rwho和ruptime服务 
sendmail:邮件服务器sendmail 
smb:Samba文件共享/打印服务 
snmpd:本地简单网络管理候进程 
squid:激活代理服务器squid 
syslog:一个让系统引导时起动syslog和klogd系统日志守候进程的脚本 
xfs:X Window字型服务器,为本地和远程X服务器提供字型集 
xntpd:网络时间服务器 
ypbind:为NIS(网络信息系统)客户机激活ypbind服务进程 
yppasswdd:NIS口令服务器 
ypserv:NIS主服务器 
gpm:管理鼠标 
identd:AUTH服务,在提供用户信息方面与finger类似

守护进程的编程要点

守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同Unix环境下守护进程的编程规则并不一致.下面将介绍Linux下守护进程的编程要点并给出详细实例.

不同Unix环境下守护进程的编程规则并不一致.所幸的是守护进程的编程原则其实都一样,区别在于具体的实现细节不同.这个原则就是要满足守护进程的特性.编程要点如下:

  1. 在后台运行.为避免挂起控制终端将Daemon放入后台执行.方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行.
  2. 脱离控制终端,登录会话和进程组.有必要先介绍一下Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID).登录会话可以包含多个进程组.这些进程组共享一个控制终端.这个控制终端通常是创建进程的登录终端.控制终端,登录会话和进程组通常是从父进程继承下来的.我们的目的就是要摆脱它们,使之不受它们的影响.方法是在第1点的基础上,调用setsid()使进程成为会话组长.(说明:当进程是会话组长时setsid()调用失败.但第一点已经保证进程不是会话组长.)setsid() 调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离.由于会话过程对控制终端的独占性,进程同时与控制终端脱离.
  3. 禁止进程重新打开控制终端.现在,进程已经成为无终端的会话组长.但它可以重新申请打开一个控制终端.可以通过使进程不再成为会话组长来禁止进程重新打开控制终端.
  4. 关闭打开的文件描述符.进程从创建它的父进程那里继承了打开的文件描述符.如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误.
  5. 改变当前工作目录.进程活动时,其工作目录所在的文件系统不能卸下.一般需要将工作目录改变到根目录.对于需要转储核心,写运行日志的进程将工作目录改变到特定目录如/tmpchdir(“/”).
  6. 重设文件创建掩模.进程从创建它的父进程那里继承了文件创建掩模.它可能修改守护进程所创建的文件的存取位.为防止这一点,将文件创建掩模清除:umask(0).
  7. 处理SIGCHLD信号.处理SIGCHLD信号并不是必须的.但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求.如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源.如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能.在Linux下可以简单地将SIGCHLD信号的操作设为SIG_IGN.这样,内核在子进程结束时不会产生僵尸进程.

守护进程实例

守护进程实例包括两部分:主程序test.c和初始化程序init.c.主程序每隔一分钟向/tmp目录中的日志test.log报告运行状态.初始化程序中的init_daemon函数负责生成守护进程.读者可以利用init_daemon函数生成自己的守护进程.
1.init.c清单
#include < unistd.h > 
#include < signal.h > 
#include < sys/param.h > 
#include < sys/types.h > 
#include < sys/stat.h > 
void init_daemon(void)  
{  
	int pid;  
	int i;  
	if(pid=fork())  
		exit(0);//是父进程,结束父进程  
	else if(pid< 0)  
		exit(1);//fork失败,退出 
 
	//是第一子进程,后台继续执行  
	setsid();//第一子进程成为新的会话组长和进程组长,并与控制终端分离  
	if(pid=fork())  
		exit(0);//是第一子进程,结束第一子进程  
	else if(pid< 0)  
		exit(1);//fork失败,退出  


	//是第二子进程,继续,第二子进程不再是会话组长  
	for(i=0;i< NOFILE;++i)//关闭打开的文件描述符  
		close(i);  
 
	chdir(“/tmp”);//改变工作目录到/tmp  
	
	umask(0);//重设文件创建掩模  
	return;  
} 
2.test.c清单
#include < stdio.h > 
#include < time.h >   
extern void init_daemon(void);//守护进程初始化函数   
main()   
{    
	FILE *fp;     
	time_t t;     
	init_daemon();//初始化为Daemon     
	while(1)//每隔一分钟向test.log报告运行状态     
	{       
		sleep(60);//睡眠一分钟       
		if((fp=fopen(“test.log”,”a”)) >=0)       
		{         
			t=time(0);         
			fprintf(fp,”I’m here at %s\n”,asctime(localtime(&t)) );        
			fclose(fp);       
		}    
	}  
}