如何写一个Linux守护进程

实现文档
如何写一个Linux守护进程

源码如下

/***********************************************************************
 *
 * 开发守护进程
 *
 **********************************************************************/

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <time.h>
#include <syslog.h>
#include <sys/resource.h>            // use getrlimit
#include <signal.h>                  // use sigaction
#include <stdlib.h>                  // use exit,system


void create_daemon(void)
{
	// 文件描述符
	int i, fd0, fd1, fd2;

	// 进程ID
	pid_t pid;

	// 资源限制
	struct rlimit rl;

	// 信号动作
	struct sigaction sa;

	// 
	// 函数:umask
	// 功能:设置文件模式的屏蔽属性。即,通过umask可禁掉某些属性。
	//
	// 目的:调用umask将文件模式创建屏蔽字设置为0,确保所有文件模式可用。
	//
	umask(0);
	
	//
	// 函数:getrlimit(RLIMIT_NOFILE, **);
	// 功能:获取资源限制,RLIMIT_NOFILE表示每个进程能打开的最大文件数。
	// 
	// 目的:获取文件描述符的信息
	//
	if(getrlimit(RLIMIT_NOFILE, &rl) < 0){
		printf("can not get file limit");
		return;
	}

	//
	// 函数:fork
	// 功能:创建子进程。子进程继承父进程的进程组ID,但具有一个新的进程ID。
	//       这确保了,子进程不是一个进程组的组长进程。
	//
	// 函数:setsid
	// 功能:创建新会话,当前进程是,新会话首进程,也是新会话的唯一进程。该进程
	//       会成为一个新进程组的组长进程,新进程组ID就是该调用进程的进程ID
	// 注意:如果调用进程是一个进程组的组长,则此函数会返回出错。为了确保不会
	//       发生这种情况,通常先调用fork,然后使其父进程终止,而子进程则继续。
	//
    // 目的:使得目标调用进程,达到以下目的。
	//       a) 成为新会话的首进程
	//       b) 成为一个新进程组的组长进程
	//       c) 没有控制终端
	//
	if((pid = fork()) < 0){
		printf("can not fork");
		return;
	}else if(pid != 0){
		exit(0);
	}
	setsid();

	//
    // 函数:sigemtpyset(sigset_t *set)
	// 功能:初始化由set指向的信号集,清楚其中所有信号。
	//
	// 函数:int sigaction(int signo, const struct sigaction * restrict act, struct sigaction *restrict oact);
	// 功能:检查或者修改与指定信号相互关联的处理动作。其中,参数signo是要检测或修改其具体动作的信号编号。
	//       若act指针非空,则要修改其动作。如果oact指针非空,则系统经由oact指针返回该信号的上一个动作。
	// 注意:SIG_IGN是常量,用于代替指向函数的指针。该函数需要一个整型参数,而且无返回值。
    //       #define SIG_DFL (void (*)())0
    //       #define SIG_IGN (void (*)())1        
	// 
	// 目的:忽略连接断开信号SIGHUP
	//
	sa.sa_handler = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if(sigaction(SIGHUP, &sa, NULL) < 0){
		printf("can not ignore SIGHUP");
		return;
	}

	// 目的:再次fork,并使父进程终止。第二个子进程作为守护进程继续运行。这样就保证了该守护进程不是会话首进程。
	//       可以防止它取得控制终端。
	if((pid = fork()) < 0){
		printf("can not fork");
		return;
	}else if(pid != 0){
		exit(0);
	}

	// 
	// 函数:chdir
	// 功能:更改当前动作目录。当前工作目录是进程的一个属性。此目录是搜索相对路径名的起点。
	//
	// 目的:使得进程不与任何文件系统联系。
	if(chdir("/usr/wlm/dev") < 0){
		printf("can not change directory");
		return;
	}	

	// 目的:关闭不再需要的文件描述符。这使守护进程不再持有从其父进程继承来的某些文件描述符。
	if(rl.rlim_max == RLIM_INFINITY){
		rl.rlim_max = 1024;
	}

	for(i = 0;i< rl.rlim_max; i++){
		close(i);
	}

	//
	// 函数:int open(const char * pathname, int oflag, ...);
	// 功能:打开或者创建一个文件。O_RDWR表示“读,写打开”
	//
    // 函数:int dup(int filedes);
	// 功能:复制一个现存的文件描述符,返回的新文件描述符一定是当前可用文件描述符中的最小数值。
	//       通常等于输入的文件描述符+1;
	//
	// 目的:守护进程打开/dev/null使其具有文件描述符0,1,2。这样,任何一个试图读标准输入,
	//       写标准输出,或者标准出错的例程都不会产生任何效果。因为守护进程并不与终端设备
	//       相关联,所以不能在终端设备上显示其输出,也无处从交互式用户那里接收输入。
	fd0 = open("/dev/null", O_RDWR);
	fd1 = dup(0);
	fd2 = dup(0);

	if(fd0 != 0 || fd1 != 1 || fd2 != 2){
		printf("unexpected file descriptors %d %d %d", fd0, fd1, fd2);
		exit(1);
	}
	
	// 重点:守护进程做任务
	//
	// 函数:int system(const char * cmdstring);
	// 功能:执行一个命令字符串。
	// 示例:system("date > file");
	//
	system("echo \"hello,world!\\n\" >>  wlm");
	time_t now;

	while(1){
		sleep(30);

		//
		// 函数:FILE * fopen(const char * restrict pathname, const char * restrict type);
		// 功能:打开一个标准I/O流
		// 注意:type="r+ 或r+b 或rb+",表示为读写而打开。
		//       type="a+", 表示open or create for reading and writing at end of file
		//
		FILE * fd = fopen("wlm", "a+");

		//
		// 函数:time_t time(time_t * calptr);
		// 功能:返回当前时间和日期
		// 注意:返回时间值。如果参数不为空,则时间值也存放在由calptr指向的单元内
		//
		time(&now);

		// 
		// 函数:int fprintf(FILE *restrict fp, const char *restrict format, ...);
		// 功能:写至指定的流
		//
		fprintf(fd, "system time:\t%s\t\t pid:%d\n", ctime(&now), getpid());

		fclose(fd);
	}
}

int main()
{	
	printf("hello,welcome to create daemon.\r\n");
	
	// 创建守护进程
	create_daemon();

	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值