认识守护进程
守护进程也成为精灵进程,是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待某些发生地事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程所实现的。 Linux系统启动时会启动很多系统服务进程。这些服务进程没有控制终端,不能直接和用户交互。其他进程都是在用户登陆或运行程序时创建,在运行结束或用户注销时终止,但系统服务进程(守护进程)不受用户登陆注销的影响,它们一直在运行着。这种进程就叫做守护进程。
- 凡是TPGID一栏写着-1的都是没有控制终端的进程
- 在COMMAND一栏用[ ]括起来的表示内核线程,这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常采用以k开头的名字,表示kernel。
- init进程我们已经很熟悉了,udevd负责维护/dev目录下的 设备⽂件,acpid负责电源管理,syslogd负责维护/var/log下的⽇志⽂件
- 守护进程通常采用以d结尾的名字,表示Daemon。
创建守护进程
创建守护进程最关键的⼀步是调⽤setsid函数创建⼀个新的Session,并成为Session Leader。
#include <unistd.h> pid_t setsid(void); 该函数调⽤成功时返回新创建的Session的id(其实也就是当前进程的id),出错返回-1。成功调用该函数的结果是:
- 创建⼀个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。
- 创建⼀个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id。
- 如果当前进程原本有⼀个控制终端,则它失去这个控制终端,成为⼀个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是⼀个普通的打开⽂件而不是控制终端了。
创建守护进程:
#include<stdio.h> #include<unistd.h> #include<signal.h> #include<stdlib.h> #include<fcntl.h> #include<sys/stat.h> void mydaemon() { int i; pid_t id; struct sigaction sa; umask(0); id = fork(); if(id < 0) { perror("fork"); exit(1); } else if(id > 0) { //father //父进程退出 exit(0); } //child //调用setid()创建新会话 setsid(); sa.sa_handler = SIG_IGN; //忽略SIGCHLD信号 sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if(sigaction(SIGCHLD,&sa,NULL) < 0) { //注册子进程退出忽略信号 return; } if(chdir("/") < 0) { //将工作目录更改为根目录 printf("child dir error!\n"); return; } //关闭不需要的文件描述符 close(0); close(1); close(2); } int main() { mydaemon(); while(1) { sleep(1); } return 0; }
dameon函数
int daemon(int nochdir, int noclose);
参数:
当 nochdir为零时,当前目录变为根目录,否则不变;
当 noclose为零时,标准输入、标准输出和错误输出重导向为/dev/null,也就是不输出任何信 息,否则照样输出。
返回值:
deamon()调用了fork(),如果fork成功,那么父进程就调用_exit(2)退出,所以看到的错误信息 全部是子进程产生的。如果成功函数返回0,否则返回-1并设置errno。
#include <stdio.h> #include <unistd.h> int main() { daemon(0,0); while(1); }