守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事情,它不需要用户输入就能运行并提供某种服务。
守护进程的父进程是init进程,因为它真正的父进程在fork出孩子后就先于自己的子程序exit推出了,所以它是一个有init领养的孤儿进程。守护进程是交互式进程,没有控制终端,所以任何输出(无论是向标准输出设备还是标准错误输出设备输出)都需要特殊处理。
Linux系统的大多数服务器就是通过守护进程实现的,且通常以字母d结尾来命令进程名,比如sshd、xinetd、crond等。
Linux系统有很多创建守护进程的方法,其中最常用的是使用daemon()函数来创建守护进程,daemon()函数的原型如下:
#include <unistd.h>
int daemon(int nochdir,int noclose);
参数nochdir:如果传入0,则daemon函数将调用进程的工作目录设置为根目录,否则保持原有的目录不变;
参数noclose:如果传入0,则daemon函数会将标准输入、标准输出、标准错误重定向到/dev/null文件中,否则不改变这些文件描述符。
该函数如果成功则返回0,否则返回-1,并设置errno。
程序清单演示了使用daemon()函数创建守护进程的用法,变为守护进程后程序每60秒打印当前的时间信息到/tmp/daemon.log文件中。
#include <stdio.h>#include <unistd.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <time.h> int main(void) { int fd; time_t curtime; if(daemon(0,0) == -1) { perror("daemon eror"); exit(-1); } fd = open("/tmp/daemon.log",O_WRONLY|O_CREAT|O_APPEND,0644); if(fd < 0) { perror("open error"); exit(-1); } while(1) { curtime = time(0); char * timestr = asctime(localtime(&curtime)); sleep(60); } close(fd); return 0; }
kill函数
kill()函数用来指定的进程发送一个指定的信号,kill()函数的原型如下:
#include <sys/types.h>
#include <signal.h>
int kill(pid_t, int sig);
kill()函数成功返回0,否则返回-1.参数pid为要发送信号的进程的PID,参数sig为需要发送的信号。
程序清单12.10演示了kill函数的用法,父进程向子进程发生SIGINT信号,并使用wait函数获取子进程的推出状态。
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> void print_exit_status(int status) { if(WIFEXITED(status)) printf("normal termination,exit status = %d\n",WEXITSTATUS(status)); else if(WIFSIGNALED(status)) printf("abnormal termination, signal number = %d\n",WIERMSIG(status)); else printf("other status\n"); } int main(int argc, char* argv[]) { pid_t pid; int status; if((pid = fork())<0) { perror("fork error"); exit(1); } else if(pid == 0) { while(1) { printf("child sleeping\n"); sleep(1); } exit(0); } else { sleep(2); printf("parent send SIGINT to child\n"); kill(pid, SIGNAL); if( wait(&status) != pid ) { perror("wait error"); exit(-1); } print_exit_status(status)l } return 0; }