Linux下使用C编写守护进程程序

linux下编译C/C++文件需要安装的依赖

  • yum -y install gcc gcc-c++ kernel-devel //安装gcc、c++编译器以及内核文件

编写守护进程的要点

  • 忽略终端的I/O信号、STOP信号、sighup信号
  • 创建子进程,结束父进程,使得子进程成为后台进程
  • 建立一个新的进程组,在此进程组中,子进程成为首进程,以使该进程脱离所有终端
  • 创建子进程,结束父进程,保证该进程不是进程组长,同时让该进程无法再打开一个新的终端
  • 关闭打开的文件描述符
  • 改变当前工作目录,使得进程不与任何文件系统联系
  • 重设文件创建掩模
  • 忽略SIGCHLD信号

用c实现的守护进程示例1-将程序变为守护进程

#include <signal.h>
#include<unistd.h>
#include<stdlib.h>
#include <sys/param.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
//#include<string.h>

int init_daemon(void)
{
	pid_t pid;
	int i;

	/**
	* 1)
	* signal.h
	* 忽略终端的I/O信号、STOP信号、sighup信号
	* 防止守护进程在没有运行起来前受到干扰从而退出或挂起
	*/
	signal(SIGTTOU, SIG_IGN);
	signal(SIGTTIN, SIG_IGN);
	signal(SIGTSTP, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	/**
	* 2)
	* unistd.h stdlib.h
	* 创建子进程
	* 结束父进程,使得子进程成为后台进程
	* 如果
	*/
	pid = fork();
	if (pid > 0)
	{
		exit(0);
	}
	else if (pid < 0)
	{
		return -1;
	}

	/**
	* 3)
	* unistd.h
	* 建立一个新的进程组
	* 在此进程组中,子进程成为首进程,以使该进程脱离所有终端
	*/
	setsid();

	/**
	* 4)
	* unistd.h stdlib.h
	* 创建子进程
	* 结束父进程,保证该进程不是进程组长,同时让该进程无法再打开一个新的终端
	*/
	pid = fork();
	if (pid > 0)
	{
		exit(0);
	}
	else if (pid < 0)
	{
		return -1;
	}

	/**
	* 5)
	* sys/param.h unistd.h
	* 关闭打开的文件描述符
	* NOFILE 为 <sys/param.h> 的宏定义,意为文件描述符最大个数,不同系统有不同限制
	*/
	for (i = 0; i < NOFILE; i++) {
		close(i);
	}

	/**
	* 6)
	* unistd.h
	* 改变当前工作目录,使得进程不与任何文件系统联系
	* 进程活动时,其工作目录所在的文件系统不能卸下,一般需要将工作目录改变到根目录
	* 对于需要转储核心,写运行日志的进程可将工作目录改变到特定目录如 /tmp
	*/
	chdir("/");

	/**
	* 7)
	* sys/types.h sys/stat.h
	* 重设文件创建掩模
	* 子进程从父进程继承的文件创建屏蔽字可能会拒绝某些许可权
	* 为防止这一点,使用unmask(0) 将屏蔽字清零
	*/
	umask(0);

	/**
	* 8)
	* signal.h
	* 忽略SIGCHLD信号
	* 如果父进程不等待子进程结束,子进程将成为僵尸进程从而占用系统资源
	* 如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能
	* 在 Linux 下可以简单地将 SIGCHLD 信号的操作设为 SIG_IGN
	*/
	signal(SIGCHLD, SIG_IGN);

	return 0;
}

int main()
{
	init_daemon();

	while (1)
	{
		system("date >> /tmp/test"); //做些事情
		sleep(1);
	}

	return 0;
}

用c实现的守护进程示例2-守护进程接收信号并作出响应

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>

int init_daemon(void)
{
	pid_t pid;
	int i;

	/**
	* 1)
	* signal.h
	* 忽略终端的I/O信号、STOP信号、sighup信号
	* 防止守护进程在没有运行起来前受到干扰从而退出或挂起
	*/
	signal(SIGTTOU, SIG_IGN);
	signal(SIGTTIN, SIG_IGN);
	signal(SIGTSTP, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	/**
	* 2)
	* unistd.h stdlib.h
	* 创建子进程
	* 结束父进程,使得子进程成为后台进程
	* 如果
	*/
	pid = fork();
	if (pid > 0)
	{
		exit(0);
	}
	else if (pid < 0)
	{
		return -1;
	}

	/**
	* 3)
	* unistd.h
	* 建立一个新的进程组
	* 在此进程组中,子进程成为首进程,以使该进程脱离所有终端
	*/
	setsid();

	/**
	* 4)
	* unistd.h stdlib.h
	* 创建子进程
	* 结束父进程,保证该进程不是进程组长,同时让该进程无法再打开一个新的终端
	*/
	pid = fork();
	if (pid > 0)
	{
		exit(0);
	}
	else if (pid < 0)
	{
		return -1;
	}

	/**
	* 5)
	* sys/param.h unistd.h
	* 关闭打开的文件描述符
	* NOFILE 为 <sys/param.h> 的宏定义,意为文件描述符最大个数,不同系统有不同限制
	*/
	for (i = 0; i < NOFILE; i++)
	{
		close(i);
	}

	/**
	* 6)
	* unistd.h
	* 改变当前工作目录,使得进程不与任何文件系统联系
	* 进程活动时,其工作目录所在的文件系统不能卸下,一般需要将工作目录改变到根目录
	* 对于需要转储核心,写运行日志的进程可将工作目录改变到特定目录如 /tmp
	*/
	chdir("/");

	/**
	* 7)
	* sys/types.h sys/stat.h
	* 重设文件创建掩模
	* 子进程从父进程继承的文件创建屏蔽字可能会拒绝某些许可权
	* 为防止这一点,使用unmask(0) 将屏蔽字清零
	*/
	umask(0);

	/**
	* 8)
	* signal.h
	* 忽略SIGCHLD信号
	* 如果父进程不等待子进程结束,子进程将成为僵尸进程从而占用系统资源
	* 如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能
	* 在 Linux 下可以简单地将 SIGCHLD 信号的操作设为 SIG_IGN
	*/
	signal(SIGCHLD, SIG_IGN);

	return 0;
}

void signal_handler(int signo)
{
	switch (signo)
	{
	case SIGINT:
		system("date>>/tmp/test"); //做些事情
		break;
	}
}

int main()
{
	init_daemon();
	signal(SIGINT, signal_handler);
	while (1)
	{
		sleep(1);
	}
	return 0;
}

停止守护进程

#首先执行以下命令查看我们守护进程的pid
ps aux | grep dameon
#找到pid后执行以下命令停止进程 xxx为pid值
kill xxx

原创文章,作者:witersen,如若转载,请注明出处:https://www.witersen.com

(3)
witersen的头像witersen
上一篇 2021年2月22日 上午10:01
下一篇 2021年3月15日 下午12:39

相关推荐

发表回复

登录后才能评论