• 会话和守护进程


    1 概念

    进程组,也称之为作业。 BSD 于 1980 年前后向 Unix 中增加的一个新特性。代表一个或多个进程的集合。每个进程都属于一个进程组。在 waitpid 函数和 kill 函数的参数中都曾使用到。操作系统设计的进程组的概念,是为了简化对多个进程的管理。

    当父进程,创建子进程的时候,默认子进程与父进程属于同一进程组。

    进程组 ID==第一个进程 ID(组长进程)。所以,组长进程标识:其进程组 ID==其进程 ID 。

    可以使用 kill -SIGKILL -进程组 ID(负的)来将整个进程组内的进程全部杀死 。

    组长进程可以创建一个进程组,创建该进程组中的进程,然后终止。只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关。
    进程组生存期:进程组创建到最后一个进程离开(终止或转移到另一个进程组) 。
    一个进程可以为自己或子进程设置进程组 ID 。

    1.1 会话

    会话:多个进程组的集合。

    创建一个会话需要注意以下 6 点注意事项:

    1. 1. 调用进程不能是进程组组长,该进程变成新会话首进程(session header)
    2. 2. 该进程成为一个新进程组的组长进程。
    3. 3. 需有 root 权限 (ubuntu 不需要)
    4. 4. 新会话丢弃原有的控制终端,该会话没有控制终端
    5. 5. 该调用进程是组长进程,则出错返回
    6. 6. 建立新会话时,先调用 fork, 父进程终止,子进程调用 setsid()

    getsid函数

    获取进程所属的会话 ID

    1. pid_t getsid(pid_t pid);
    2. // 成功:返回调用进程的会话 ID;失败: -1,设置 errno
    3. // pid 为 0 表示察看当前进程 session ID

    ps ajx 命令查看系统中的进程。
    参数 a 表示不仅列当前用户的进程,也列出所有其他用户的进程;
    参数 x 表示不仅列有控制终端的进程,也列出所有无控制终端的进程;
    参数 j 表示列出与作业控制相关的信息。

    setsid函数

    创建一个会话,并以自己的 ID 设置进程组 ID,同时也是新会话的 ID。

    1. pid_t setsid(void);
    2. // 成功:返回调用进程的会话 ID;失败: -1,设置 errno

     三合一:gid、sid、pid

    测试

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <unistd.h>
    5. #include <pthread.h>
    6. #include <signal.h>
    7. #include <sys/wait.h>
    8. int main(int argc, char *argv[])
    9. {
    10. pid_t pid;
    11. if ((pid = fork()) < 0)
    12. {
    13. perror("fork error\n");
    14. exit(1);
    15. }
    16. else if (pid == 0)
    17. {
    18. printf("child process PID = %d\n", getpid()); // 进程id
    19. printf("Group ID of child GID = %d\n", getpgid(0)); // 进程组id
    20. printf("session ID of child SID = %d\n", getsid(0)); // 会话id
    21. sleep(10);
    22. setsid(); // 子进程不是组长进程,可以成为新会话首进程,且成为组长进程,该进程组长id即为会话
    23. printf("Change:\n");
    24. printf("child process PID = %d\n", getpid()); // 进程id
    25. printf("Group ID of child GID = %d\n", getpgid(0)); // 进程组id
    26. printf("session ID of child SID = %d\n", getsid(0)); // 会话id
    27. sleep(20);
    28. exit(0);
    29. }
    30. return 0;
    31. }

    执行

    2 守护进程

    2.1 什么是守护进程

    1 在linux系统中,我们会发现在系统启动的时候有很多的进程就已经开始跑了,也称为服务,这也是我们所说的守护进程。
    2 守护进程(daemon)是生存期长的一种进程,没有控制终端。
    3 它们常常在系统引导装入时启动,仅在系统关闭时才终止。
    4 UNIX系统有很多守护进程,守护进程程序的名称通常以字母“d”结尾:例如,syslogd 就是指管理系统日志的守护进程

    5 通过ps进程查看器 ps -efj 的输出实例,内核守护进程的名字出现在方括号中,大致输出如下:

    守护进程:

    daemon进程。通常运行于操作系统后台,脱离控制终端。一般不与用户直接交互。周期性的等待某个事件发生或周期性执行某一动作。
    不受用户登录注销影响。通常采用以d结尾的命名方式。
    创建守护进程,最关键的一步是调用setsid函数创建一个新的Session,并成为Session Leader。

    2.2 守护进程创建步骤

    1. fork子进程,让父进程终止。
    2. 子进程调用 setsid() 创建新会话
    3. 通常根据需要,改变工作目录位置 chdir(), 防止目录被卸载。(U盘)
    4. 通常根据需要,重设umask文件权限掩码,影响新文件的创建权限。 022 -- 755 0345 ---
    432 r---wx-w- 422
    5. 通常根据需要,关闭/重定向(0/1/2) dev/null 文件描述符
    6. 守护进程 业务逻辑。while()

    2.3 守护进程代码实现(重点)

    主要是理解一些概念。

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <unistd.h>
    5. #include <pthread.h>
    6. #include <fcntl.h>
    7. #include <sys/stat.h>
    8. int main(int argc, char *argv[])
    9. {
    10. pid_t pid; // 进程
    11. int res; // 返回值
    12. int fd; // 文件描述符
    13. pid = fork();
    14. if (pid > 0)
    15. { // 父进程
    16. exit(1);
    17. }
    18. else
    19. { // 子进程
    20. pid = setsid();
    21. if (pid == -1)
    22. {
    23. perror("setsid error\n");
    24. exit(1);
    25. }
    26. res = chdir("/home/winter/linuxStudy"); // 改变工作目录位置
    27. if (res == -1)
    28. {
    29. perror("chdir error\n");
    30. exit(1);
    31. }
    32. umask(0022); // 改变文件访问权限掩码
    33. close(STDIN_FILENO); // 关闭文件描述符0
    34. fd = open("/dev/null", O_RDWR); // 读写权限打开 fd就是0
    35. if (fd == -1)
    36. {
    37. perror("open error\n");
    38. exit(1);
    39. }
    40. dup2(fd, STDOUT_FILENO); // 重定向,将STDOUT_FILENO指向fd
    41. dup2(fd, STDERR_FILENO);
    42. // 模拟守护进程业务
    43. while (1)
    44. ;
    45. }
    46. return 0;
    47. }

    执行

    这个daemon进程就不会受到用户登录注销影响。要想终止,就必须用kill命令。

  • 相关阅读:
    Elasticsearch安全又双叒叕出问题? 搜索引擎该怎么选
    类与对象(十六)----封装encapsulation
    halcon安装以及配置
    前端之道:你知道的Cookie有多少?
    腾讯云我的世界mc服务器配置选择(价格值得)
    【裴蜀定理】CF1055C Lucky Days
    python sqlalchemy(ORM)- 01 简单使用
    Kotlin 开发Android app(九):Android两大布局LinearLayout和RelativeLayout
    SNARK性能及安全——Verifier篇
    【c++刷题Day1】专题1背包T2
  • 原文地址:https://blog.csdn.net/Zhouzi_heng/article/details/125404803