守护进程
守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程实现的,比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任务。比如,作业规划进程crond,打印进程lpd等。
其特征如下:
- 后台运行
守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。 - 独立于其运行前的环境
守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符,控制终端,会话和进程组,工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。 启动方式
守护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc.d中启动,可以由作业规划进程crond启动,还可以由用户终端(通常是shell)执行。除了以上这些特征外,守护进程与普通进程基本上没有什么区别。实际上,编写守护进程也就是按照上述的守护进程特征把一个普通进程改造成为守护进程。
实现
protect.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define EXEC_FAIL_EXITCODE 110
int main(int argc, char** argv) {
if (argc < 2) {
puts("Usage: protect service_process arg...");
return -10;
}
// prepare child argv
char** child_argv = (char**)malloc((argc)*sizeof(char*));
int i = 1, j = 0;
for (; i < argc; ++i, ++j) {
int len = strlen(argv[i]) + 1;
child_argv[j] = (char*)malloc(len);
strncpy(child_argv[j], argv[i], len);
}
child_argv[argc-1] = NULL;
pid_t pid = fork();
if (pid < 0) {
puts("fork failed.");
exit(-20);
}
if (pid > 0) {
exit(0); // exit parent process, get rid of terminal
}
if (pid == 0) {
setsid(); // create a new session, become process group leader
// nochdir
// chdir("/");
// noclose
// close stdin,stdout,stderr
// for (i = 0; i < 3; ++i) {
// close(i);
// }
for(;;) {
pid_t pid2 = fork();
if (pid2 < 0) {
exit(-30);
}
if (pid2 > 0) {
int status = 0;
waitpid(pid2, &status, 0); // wait service process
if (WIFEXITED(status) && WEXITSTATUS(status) == EXEC_FAIL_EXITCODE){
exit(-40);
}
}
if (pid2 == 0) {
int ret = execvp(argv[1], child_argv); // exec service
if (ret < 0) {
printf("exec %s failed.\n", argv[1]);
exit(EXEC_FAIL_EXITCODE);
}
}
}
}
return 0;
}
编译gcc protect.c -o protect
运行示例:
./protect gnome-system-monitor
试着用Alt-F4关闭窗口,可以发现马上又重启了