1、 进程组 组长不能创建新的 会话。
其它进程可以创建新的会话,创建后既成为会话首领,同时失去控制终端。
2、 会话首领可以重新打开控制终端
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <sys/param.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include <fcntl.h>
8 #include <signal.h>
9
10 void my_daemon() {
11 int pid, fd;
12
13 // 1.转变为后台进程
14 if ((pid = fork()) == -1) exit(1);
15 if (pid != 0) exit(0); // 父进程(前台进程)退出
16
17 // 2.离开原先的进程组,创建一个新会话,并脱离原终端。原终端断开后会通知原会话的控制进程,并不会通知此会话
18 if (setsid() == -1) exit(1); // 开启一个新会话,此PID为会话首进程
19
20 // 3.会话首进程,有权利再次连接终端。再fork一次,会话首进程退出,禁止子进程再次打开控制终端
21 if ((pid = fork()) == -1) exit(1);
22 if (pid != 0) exit(0); // 父进程(会话领头进程)退出
23
24 // 4.关闭打开的文件描述符,避免浪费系统资源
25 for (int i = 0; i < NOFILE; i++)
26 close(i);
27
28 // 5.改变当前的工作目录,避免卸载不了文件系统
29 if (chdir("/") == -1) exit(1);
30
31 // 6.重设文件掩码,防止某些属性被父进程屏蔽
32 if (umask(0) == -1) exit(1);
33
34 // 7.重定向标准输入,输出,错误流,因为守护进程没有控制终端
35 if ((fd = open("/dev/null", O_RDWR)) == -1) exit(1); // 打开一个指向/dev/null的文件描述符
36 dup2(fd, STDIN_FILENO);
37 dup2(fd, STDOUT_FILENO);
38 dup2(fd, STDERR_FILENO);
39 close(fd);
40
41 // 8.本守护进程的子进程若不需要返回信息,那么交给init进程回收,避免产生僵尸进程
42 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) exit(1);
43 }
44
45 #define INTERVAL 2
46
47 int main(int argc, char *argv[]) {
48 my_daemon(); // 首先使之成为守护进程
49
50 int t = 0;
51 FILE *fp = fopen("/root/tmp.txt", "a");
52 fprintf(fp, "ppid = %d, pid = %d, sid = %d, pgrp = %d\n", getppid(), getpid(), getsid(0), getpgrp());
53 fflush(fp);
54
55 do { // 测试此后台进程,每INTERVAL秒打印当前时间t,30秒后退出此后台进程
56 fprintf(fp, "%d\n", t);
57 fflush(fp); // 输出缓冲区内容到文件中
58 sleep(INTERVAL);
59 t += INTERVAL;
60 } while(t < 30);
61
62 fclose(fp);
63
64 return 0;
65 }
保存为daemon.c
编译命令 gcc daemon.c
运行 ./a.out
查看tmp.txt文件内容 cat /root/tmp.txt