守护进程

守护进程是在后台运行且不与任何控制终端关联的进程。

守护进程没有控制终端通常源于它们由系统初始化脚本启动。然而守护进程也可能从某个终端由用户在shell提示符下键入命令行启动,这样的守护进程必须亲自脱离与控制终端的关联,从而避免与作业控制、终端会话管理、终端产生信号等发生任何不期望的交互,也可以避免在后台运行的守护进程非预期地输出到终端。

编程实例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/resource.h>

void daemon()
{
	pid_t pid;
	struct rlimit rl;
	struct sigaction sa;

	umask(0);

	if ((pid = fork()) < 0)
		exit(-1);
	else if (pid > 0)
		exit(0);

	setsid();
	printf("pid:%d sid:%d pgid:%d\n", getpid(), getsid(0), getpgid(0));

	sa.sa_handler = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if (sigaction(SIGHUP, &sa, NULL) < 0)
		exit(-1);

	if ((pid = fork()) < 0)
		exit(-1);
	else if (pid > 0)
		exit(0);

	printf("pid:%d sid:%d pgid:%d\n", getpid(), getsid(0), getpgid(0));
	
	if (chdir("/") < 0)
		exit(-1);

	int fd_size = getdtablesize();
	printf("fd_size:%d\n", fd_size);
	for (int fd = 0; fd < fd_size ; fd++)
		close(fd);

	int fd0 = open("/dev/null", O_RDWR);
	int fd1 = dup(0);
	int fd2 = dup(0);

	if (fd0 != 0 || fd1 != 1 || fd2 != 2)
		exit(-1);

	rl.rlim_cur = 65535;
	rl.rlim_max = 65535;
	setrlimit(RLIMIT_NOFILE, &rl);
}

int main()
{
	daemon();
	return 0;
}


1.调用umask将文件模式创建屏蔽字设置为0。由继承得来的文件模式创建屏蔽字可能会拒绝设置某些权限。

2.第一次调用fork()后,当父进程终止时,shell认为该命令已执行完毕。这样子进程就自动在后台运行,子进程继承了父进程的进程组id。

3.子进程调用setsid()后,子进程成为会话组长(sid==pid),也是进程组组长(pgid==pid),并且脱离了原来的控制终端。

4.第二次调用fork()后,父进程终止,子进程id不等于父进程的sid。由于打开一个控制终端的前提条件是该进程必须是会话组长,所以该进程再也无法打开新的控制终端。

5.忽略SIGHUP信号,第二次fork后,父进程终止时,其会话中的所有进程都会受到SIGHUP信号,所以需要忽略。

6.调用chdir()改变当前工作目录,防止占用可卸载的文件系统。

7.关闭所有文件描述符,再将stdin、stdout、stderr重定向到/dev/null。

8.最后还可以重新设置系统资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值