Linux进程间关系之终端与终端登录

终端

介绍

在Linux/Unix系统中,用户总是通过终端登录系统后得到一个shell进程,进而在shell命令行上输入命令与系统进行交互。说白了,终端就是系统与用户进行“交流”的窗口,而所有在这个终端下创建的进程都“属于”这个终端。这个终端也就是这些进程的控制终端
(控制终端是保存在PCB信息中的,而fork子进程会复制PCB中的信息。所以shell创建的所有进程的控制终端都是这个终端。)
我们在图形化界面下使用Linux,打开一个叫Terminal的窗口才能进行操作,Terminal就是终端的意思,打开一个会话窗口就是打开一个终端。
这里写图片描述
默认情况下,每个进程的标准输入,标准输出,标准错误输出都指向控制终端。所以进程从标准输入就是读用户的键盘输入,进程的标准输出或者标准错误输出就是输出到显示器上。

设备

无论怎么学Linux,都要注意,Linux下一切皆文件。终端也是一种文件,我们通常管它叫做设备文件。这个设备文件通常在/dev目录下,名字为“tty+编号”。
这里写图片描述
但是注意,上图中有个没有加编号的tty文件,每个进程都可以通过这个特殊设备文件/dev/tty来访问它的控制终端。我们可以从上图看出,每个终端都对应一个独自的设备文件,但/dev/tty文件提供了一个通用的接口,一个进程要想访问终端,可以通过这个设备文件,也可以通过它自己的设备文件。

函数ttyname

我们可以利用函数ttyname通过文件描述符来查看当前对应的终端名称。

#include<unistd.h>
char *ttyname(int fd);

参数fd即为文件描述符。

示例:

#include<stdio.h>
#include<unistd.h>
int main()
{
    printf("%s\n",ttyname(0));
    printf("%s\n",ttyname(1));
    printf("%s\n",ttyname(2));
    return 0;
}

执行结果:
这里写图片描述

当前终端不要关,再打开一个终端再运行一次看看:
这里写图片描述

除了用文件描述符和函数ttyname之外,我们还通过指令来查看:

who am i//注意,中间是有空格的。

终端登录

虚拟终端

所谓的终端设备就是我们的硬件设备,鼠标,键盘,显示器等。显而易见,我们只有这一套硬件终端设备。而终端却能打开很多。比如我们可以通过Ctrl-Alt-F1~F6切换到6个字符终端,相当于拥有了6套虚拟终端设备。我们称之为虚拟终端
设备⽂件/dev/
tty0表 示当前虚拟终端,⽐如切换到Ctrl-Alt-F1的字符终端时/dev/tty0就表示/dev/tty1,切换到Ctrl-Alt- F2的字符终端时/dev/tty0表示/dev/tty2,就像/dev/tty同样也是一个通用的接口,但它不能表 示图形终端窗口所对应的终端。

硬件驱动程序与线路规程

内核中处理终端设备的模块包括硬件驱动程序和线路规程。驱动程序好理解,线路规程是什么呢?
线路规程也属于一个软件驱动,它主要负责接收硬件发来的数据或者将发送给硬件的数据翻译成硬件可以理解的数据。比如从键盘输入Ctrl+c让程序终止,硬件并不能理解Ctrl+c是什么东西,所以需要线路规程帮它翻译成SIGINT信号。我看来,线路规程不过是硬件的助理兼翻译。

这里写图片描述

输入输出缓冲区

终端设备有输入输出缓冲区。如下图所示:

这里写图片描述

这里的输入输出是指硬件相对于系统,从键盘输入数据,从显示屏输出数据。
以输入队列为例:用户从键盘输入指令,经线路规程过滤进入输入队列,进程调用系统调用read读取指令,一般以先入先出的顺序读取。当输入队列满时,再输入数据就会丢失。
<回显>是指将输入的指令回显到屏幕上,使我们可以看到。比如我们在shell命令行上输入ls命令,显示器就会将ls字符输出,使我们可见。有时候系统也是不回显的,比如当你切到root用户输入密码时,此时你输入的密码就不会被系统回显至显示器。

终端登录过程

当系统启动时,通常为创建一个ID为1的进程init,我们称之为1号进程。当要启动一个终端设备时,init会读取配置文件/etc/inittab确定需要打开哪些终端,每一个终端都对应配置文件的一行。其中你会发现每一行都会有类似于:

/sbin/getty 9600 tty1

这句话的意思是init进程打开fork/exec命令,exec getty程序。
(不同的Linux版本肯会有不同的配置文件,不一定都在/etc/inittab文件内)
通过上面我们已经可以认识到终端登录的第一步了,如下图:
这里写图片描述

当getty程序启动后,getty会对终端设备调用open函数,以读,写方式打开终端。(如果设备是调制解调器,则open可能会在设备驱动程序中滞留,直到用户拨号调制解调器,并且线路被接通)
当终端打开后,文件描述符0,1,2就会被设置到该终端设备。之后会输出提醒,提醒用户输入账号。到此getty的任务完成,第二步也完成。

之后getty会exec login程序,提示用户输入密码(此时终端回显被关闭)。然后验证密码是否正确。

  • 若密码正确:login程序会设置一些环境变量,设置当前工作目录为该用户的主目录,然后exec运行shell。
  • 若密码错误:login程序终止,init重新从第一步开始执行。

总流程图如下:
这里写图片描述

注意,从getty到login再到login,其实都是同一个进程。exec只是进行了数据代码的切换,并没有进行进程切换。这个进程始终是被init fork出的那个子进程。所以他们的父进程始终为init。由于fork子进程会继承PCB的信息,所以由bash创建的所有进程的祖先进程都是init。

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LLZK_/article/details/59097239
个人分类: Linux学习笔记
所属专栏: Linux学习之路
上一篇Linux多线程编程(四)-----读写锁
下一篇Linux例行性工作调度cron
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭