守护进程,也即后台程序。不依赖于终端存在,即终端关闭进程依旧在后台默默的运行,我们可以通过ps命令查看计算机上的进程,其实守护进程还是很多的。
ps -ef
输出
UID PID PPID C STIME TTY TIME CMD ... .... .... . .. .. ... .......................... root 3898 3876 0 01:23 ? 00:00:03 hald-addon-storage: polling /dev root 3919 1 0 01:23 ? 00:00:00 /usr/bin/hidd --server root 3949 1 0 01:23 ? 00:00:00 automount root 3971 1 0 01:23 ? 00:00:00 ./hpiod root 3976 1 0 01:23 ? 00:00:00 python ./hpssd.py root 4017 1 0 01:23 ? 00:00:00 /usr/sbin/sshd root 4044 1 0 01:23 ? 00:00:00 xinetd -stayalive -pidfile /var/ root 4067 1 0 01:23 ? 00:00:00 sendmail: accepting connections smmsp 4075 1 0 01:23 ? 00:00:00 sendmail: Queue runner@01:00:00 root 4090 1 0 01:23 ? 00:00:00 gpm -m /dev/input/mice -t exps2 root 4104 1 0 01:23 ? 00:00:00 crond xfs 4142 1 0 01:23 ? 00:00:00 xfs -droppriv -daemon root 4169 1 0 01:23 ? 00:00:00 /usr/sbin/atd avahi 4200 1 0 01:23 ? 00:00:00 avahi-daemon: running [localhost avahi 4201 4200 0 01:23 ? 00:00:00 avahi-daemon: chroot helper root 4232 1 0 01:23 ? 00:00:00 /usr/sbin/smartd -q never root 4236 1 0 01:23 ? 00:00:00 login -- root root 4237 1 0 01:23 tty2 00:00:00 /sbin/mingetty tty2 root 4241 1 0 01:23 tty3 00:00:00 /sbin/mingetty tty3 root 4242 1 0 01:23 tty4 00:00:00 /sbin/mingetty tty4 root 4243 1 0 01:23 tty5 00:00:00 /sbin/mingetty tty5 root 4261 1 0 01:23 tty6 00:00:00 /sbin/mingetty tty6 root 4292 1 0 01:23 ? 00:00:00 /usr/bin/python -tt /usr/sbin/yu root 4294 1 0 01:23 ? 00:00:00 /usr/libexec/gam_server root 4388 4236 0 01:26 tty1 00:00:00 -bash root 4474 4017 0 01:27 ? 00:00:01 sshd: root@pts/0 root 4509 4474 0 01:28 pts/0 00:00:00 -bash root 4899 4017 0 01:37 ? 00:00:00 sshd: root@pts/1 root 4914 4899 0 01:37 pts/1 00:00:00 -bash
那么 TTY 终端为 ? 问号程序就是守护进程, 而其他的, 比如 tty2 这是一个终端的名称, 如果使用这个终端登录的用户退出, 那么所有这个终端下的程序都会结束掉.
而守护进程不依赖于终端, 所以即使终端退出(比如远程连接的putty)只要电脑还开着, 那么它就默默的在后台运行.
setsid() 函数
setsid() 调用成功后,当前进程会脱离原有的会话(session, 终端与会话是对应的), 成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。
简单点可以理解, 刚登陆的时候有个session产生, 这个session与终端对应. 如果我把这个终端关掉(例如关掉连接中的 putty ) 那么与之相关的session还有进程组都会被干掉。
这个还是还比较好理解的,如果我用putty登陆,上面开了很多程序, 这个时候我把putty关掉, 那么系统也会把我刚刚登陆的这个putty(终端)上开的程序神马的统统关掉.
那么, 我不希望系统关掉我的程序, 我想让我的程序在后台一直运行, 那么就只有让程序脱离于putty对应的session和进程组(setsid就可以做到)
那么, 需要注意的是:进程组组长不能创建守护进程. 其实就是进程组组长不能调用 setsid , 因为他本身就是组长了.
下面看下实现的实例:
#include <stdio.h> #include <stdlib.h> // exit() #include <unistd.h> // fork() setsid() chdir() close() #include <sys/types.h> // fork() umask() #include <sys/stat.h> // umask() // 与终端无关,在后台默默运行的守护进程 void mydaemon(int ischdir,int isclose) { // 调用setsid() 的不能是进程组组长,当前程序有可能是进程组组长 pid_t pid = fork(); // 非子进程则退出 if(pid != 0) exit(-1); // 父进程退出,留下子进程 // 创建一个新的会话期,从而脱离原有的会话期 // 进程同时与控制终端脱离 setsid(); // 此时子进程成为新会话期的领导和新的进程组长 // 但这样的身份可能会通过fcntl去获到终端 pid = fork(); // 非子进程则退出 if(pid != 0) exit(-1); // 此时留下来的是孙子进程,再也不能获取终端 // 通常来讲, 守护进程应该工作在一个系统永远不会删除的目录下 if(ischdir == 0) { chdir("/"); } // 关闭输入输出和错误流 (通过日志来查看状态) if(isclose == 0) { close(0); close(1); close(2); } //去掩码位 umask((mode_t)0);//sys/stat.h } int main(int argc, char *argv[]) { mydaemon(1,1); while(1) ; exit(EXIT_SUCCESS); }
gcc mydaemon.c -o mydaemon ./mydaemon
运行之后应该是什么效果都没有的, 这个时候通过ps命令来查看
ps -ef
输出:
其他省略n项... root 4388 4236 0 01:26 tty1 00:00:00 -bash root 4474 4017 0 01:27 ? 00:00:01 sshd: root@pts/0 root 4509 4474 0 01:28 pts/0 00:00:00 -bash root 4899 4017 0 01:37 ? 00:00:00 sshd: root@pts/1 root 4914 4899 0 01:37 pts/1 00:00:00 -bash root 9231 1 97 04:40 ? 00:01:19 ./mydaemon root 9278 4509 0 04:41 pts/0 00:00:00 ps -ef
发现我们的程序已经运行了起来, 并且终端处是 ? 问号, 即成为了不依赖于任何终端而存在后台程序.
那么, 虽然有点小残忍, 但是这里还是要顺便提一下怎么杀死这样的进程:
#向进程id为9231的进程发送 SIGKILL 信号 kill -9 9231
详细见: Linux 查看进程和删除进程