一、什么是守护进程
Linux服务器在启动时需要启动很多系统服务(其实Windows也这样),它们向本地或网络用户提供了Linux的系统功能接口,直接面向应用程序和用户。提供这些服务的程序是由运行在后台的守护进程(daemons原意精灵)来执行的。
守护进程是生存期很长的一种进程。它们独立于控制终端并且周期性地执行某种任务(例如预处理和换输出机制)或等待处理某些发生的事件(例如ftp、ssh)。它们常常伴随着Linux系统启动时启动,关闭时关闭。linux系统有很多守护进程,大多数服务器都是用守护进程实现的。另外,某些守护进程还协助完成了很多系统任务,比如负责计划任务的atd和crond、负责打印的lqd等。
二、怎么创建守护进程
守护进程的创建(编程)步骤:
1. 创建子进程,父进程退出:
所有工作在子进程中进行
形式上脱离了控制终端
2. 在子进程中创建新会话:
调用setsid()函数
使子进程完全独立出来,脱离控制
3. 改变当前目录为根目录:
chdir()函数
防止占用可卸载的文件系统
也可以换成其它路径
4. 重设文件权限掩码:
调用umask()函数
防止继承的文件创建屏蔽字拒绝某些权限
增加守护进程灵活性
5. 关闭文件描述符:
继承的打开文件不会用到,浪费系统资源,无法卸载
因为当失去终端的时候,原来的文件描述符0,1,2本应该指向终端的tty,
但是失去终端的时候就没有办法进行指向终端了,所以要关闭
6. 开始执行守护进程核心工作
7. 守护进程退出处理
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <fcntl.h> 4 void daemonize(void) 5 { 6 pid_t pid; 7 /* 8 * 成为一个新会话的首进程,失去控制终端 9 */ 10 if ((pid = fork()) < 0) 11 { 12 perror("fork"); 13 exit(1); 14 } 15 else if (pid != 0) /* in parent close parent proccess */ 16 exit(0); 17 18 setsid();// 在子进程中创建新会话,使子进程完全独立出来,脱离控制 19 20 /* 21 * 改变当前工作目录到/目录下. 22 */ 23 if (chdir("/") < 0) 24 { 25 perror("chdir"); 26 exit(1); 27 } 28 /* 设置umask为0 */ 29 umask(0); 30 /* 31 * 重定向0,1,2文件描述符到/dev/null(即关闭) 32 * 因为已经失去控制终端,再操作0,1,2没有意义. 33 */ 34 close(0); 35 open("/dev/null", O_RDWR);//此时0的号文件描述符为/dev/null 36 dup2(0, 1); 37 dup2(0, 2); 38 // 而标准输入0,标准输出1,标准错误2,都指/dev/null文件 39 // 而/dev/null文件就相当于关闭 40 } 41 int main(void) 42 { 43 daemonize(); 44 while(1) 45 { 46 ;/* 在此循环中可以实现守护进程的核心工作*/ 47 } 48 }
运行这个程序,将使它变成一个守护进程,不再和当前终端关联。用ps命令看不到,必须运行带x参数的ps命令才能看到。另外还可以看到,用户关闭终端窗口或注销也不会影响守护进程的运行。
而要守护进程和终端脱离是为了防止终端被关闭的时候守护进程也被关闭。
举例:(每隔3秒钟向文件time中写入当前时间)
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <fcntl.h> 4 #include <string.h> 5 void daemonize(void) 6 { 7 pid_t pid; 8 /* 9 * 成为一个新会话的首进程,失去控制终端 10 */ 11 if ((pid = fork()) < 0) 12 { 13 perror("fork"); 14 exit(1); 15 } 16 else if (pid != 0) /* in parent close parent proccess */ 17 exit(0); 18 19 setsid();//在子进程中创建新会话,使子进程完全独立出来,脱离控制 20 21 /* 22 * 改变当前工作目录到/目录下. 23 */ 24 if (chdir("/") < 0) 25 { 26 perror("chdir"); 27 exit(1); 28 } 29 /* 设置umask为0 */ 30 umask(0); 31 /* 32 * 重定向0,1,2文件描述符到/dev/null(即关闭) 33 * 因为已经失去控制终端,再操作0,1,2没有意义. 34 */ 35 close(0); 36 open("/dev/null", O_RDWR);//此时0的号文件描述符为/dev/null 37 dup2(0, 1); 38 dup2(0, 2); 39 //而标准输入0,标准输出1,标准错误2,都指/dev/null文件 40 //而/dev/null文件就相当于关闭 41 } 42 int main(void) 43 { 44 char buf[1024] = {0}; 45 time_t t; 46 int fd = open("time", O_RDWR | O_CREAT, 0777); 47 if(fd < 0) 48 { 49 perror("open"); 50 exit(0); 51 } 52 53 daemonize(); 54 while(1)/* 在此循环中可以实现守护进程的核心工作*/ 55 { 56 time(&t); //距离1970.1.1 00:00:00 的秒数 57 ctime_r(&t, buf); //把得到的秒数转换为当前的时间 58 write(fd, buf, strlen(buf)); 59 memset(buf, 1024*sizeof(char), 0); 60 sleep(3); 61 62 } 63 } 64 65 66 67 68 其中对时间处理函数的使用举例: 69 #include <stdio.h> 70 #include <time.h> 71 72 int main(void) 73 { 74 char buf[1024] = {0}; 75 time_t t; 76 77 time(&t); //距离1970.1.1 00:00:00 的秒数 78 ctime_r(&t, buf); //把得到的秒数转换为当前的时间 79 printf("%s",buf); //格式为 Fri Feb 12 06:58:12 2016 最后一换行符 80 }