Linux系统编程(会话和进程)


前言

本篇文章我们来讲解会话和进程的概念,会话大家可能比较少见,他的英文名称叫session。

一、会话的概念

在Linux中,会话(Session)是指用户与操作系统交互的一段时间。Linux下的会话概念是基于终端(Terminal)的,而终端可以是物理终端、虚拟终端(例如TTY)或远程连接(如SSH)。
以下是Linux中会话的几个关键概念:

1.控制终端:
在一个会话中,通常会存在一个控制终端,为用户提供输入和输出的交互界面。用户通过控制终端与操作系统进行交互,包括输入命令、运行程序和查看输出。

2.终端会话:
一个用户可以在控制终端上启动一个或多个终端会话。每个终端会话都是一个独立的进程组,包含一个前台进程组和零个或多个后台进程组。

3.前台进程组:
前台进程组是当前用户正在交互的进程组。当用户从控制终端输入命令时,命令将发送给前台进程组的前台进程进行处理。只有一个进程组可以处于前台状态。

4.后台进程组:
后台进程组是在终端会话中运行的进程组,但没有用户输入交互。用户可以将进程从前台切换到后台,使其在后台运行而不阻塞终端。

5.会话管理程序:
Linux通过会话管理程序(session manager)来管理终端会话。会话管理程序负责创建和管理会话,设置控制终端,并在会话结束时清理资源。

6.会话注销和断开:
当用户注销或断开与终端的连接时,会话通常会终止。会话终止会导致终端上的所有进程(前台和后台)收到相应的信号来进行清理和终止。

会话在Linux中是重要的概念,它提供了用户与操作系统之间的交互环境,并管理用户的进程组。了解和理解Linux中的会话概念对于正确地管理和控制用户的交互行为是至关重要的。

二、会话和终端的区别

会话(Session)和终端(Terminal)是两个相关但不完全相同的概念。

会话是指用户与操作系统或应用程序之间的交互过程,涉及到用户的身份验证、持久性连接、状态保持等方面。在会话中,用户可以通过终端或其他交互方式与系统进行通信。

终端是一个提供用户与计算机交互的设备或界面,用户可以通过终端输入命令、查看输出和与系统进行交互。终端可以是物理设备(如物理终端设备、控制台)或虚拟设备(如虚拟终端、SSH连接)。终端提供了用户与系统之间的输入和输出通道。

下面是它们之间的区别:

1.概念层面:

会话是指用户与操作系统或应用程序之间的交互过程,包括用户的身份验证、持久性连接和状态保持等。
终端是用户与计算机交互的设备或界面,它提供了用户输入和输出的通道。

2.关联:

会话和终端通常是相关的。一个用户可以通过终端设备或虚拟终端启动一个会话,并在会话中与系统进行交互。
一个终端可以有多个会话,例如在同一终端设备上打开多个虚拟终端会话。

3.功能:

会话涉及用户的身份验证、状态保持和持久性连接等功能,用于管理用户与系统之间的交互。
终端提供了用户输入命令、查看输出和与系统进行交互的功能。

4.物理性质:

会话是一个抽象的概念,表示用户与系统的交互过程,不涉及具体的物理设备。
终端可以是物理设备(如键盘、显示器)或虚拟设备(如虚拟终端、SSH连接)。

在这里插入图片描述

当命令行shell执行新的命令创建出新的进程时:

使用&创建新的进程,新建的进程是后台进程,自己依然是前台进程。

不使用&创建新的进程,新建的进程是前台进程,自己被设置为后台进程。

三、终端进程组标识

在Linux中,每个终端会话都有一个唯一的进程组标识符(Process Group ID,PGID)。终端进程组标识是为了实现作业控制和进程管理而引入的。
每个终端会话中的进程都隶属于一个进程组。当用户在终端上启动一个新的进程时,默认情况下,该进程会被分配到同一终端会话的进程组中。

终端进程组标识具有以下特点:

1.会话首进程的进程组标识:
在每个会话中,会有一个会话首进程(session leader)创建该会话,会话首进程的进程组标识与会话ID(Session ID,SID)相同。

2.前台进程组:
在终端会话中,只能有一个前台进程组(foreground process group)。该前台进程组通常接收来自终端的用户输入,并将输出发送到终端。用户在终端上输入的命令会被发送给前台进程组中的前台进程。

3.后台进程组:
终端会话可以同时包含多个后台进程组(background process group)。后台进程组是在终端会话中运行的进程组,但不接受用户输入。后台进程组可以在终端会话运行而不阻塞终端。

通过使用终端进程组标识,系统可以实现对作业控制的管理,包括在前台或后台运行进程组、切换前后台进程组、发送信号等。
要查看当前终端进程组标识,您可以使用echo $$命令。该命令会输出当前Shell进程的进程ID(PID),该Shell进程所在的进程组ID就是终端进程组标识。

四、创建会话

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    
    
    pid_t pid;

    // 创建一个子进程
    pid = fork();
    if (pid < 0) {
    
    
        fprintf(stderr, "无法创建子进程\n");
        return 1;
    } else if (pid == 0) {
    
    
        // 子进程

        // 创建一个新的会话
        if (setsid() < 0) {
    
    
            fprintf(stderr, "无法创建新会话\n");
            return 1;
        }

        // 关闭标准输入、输出和错误输出
        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);

        // 从这里开始,子进程就可以执行会话中的任务

        // 示例:打开一个日志文件并写入日志
        FILE* logFile = fopen("/var/log/mylog.txt", "w");
        if (logFile == NULL) {
    
    
            fprintf(stderr, "无法打开日志文件\n");
            return 1;
        }

        fprintf(logFile, "会话已启动\n");
        fprintf(logFile, "执行一些任务\n");

        // 关闭日志文件
        fclose(logFile);

        // 子进程完成任务后退出
        exit(0);
    } else {
    
    
        // 父进程
        // 这里可以选择等待子进程完成或继续执行其他任务
        printf("子进程的PID:%d\n", pid);
    }

    return 0;
}

这个示例程序创建了一个子进程,子进程通过调用setsid()函数创建一个新的会话,然后关闭标准输入、输出和错误输出,开始执行会话中的任务(这里仅为示例,可以根据具体需求进行修改)。父进程可以选择等待子进程完成或继续执行其他任务。

总结

本篇文章就讲解到这里。

猜你喜欢

转载自blog.csdn.net/m0_49476241/article/details/133047934