linux一切皆文件之tty字符设备(深刻理解sshd建立pty的过程) (五)

1、知识准备

一、在linux中,一切皆为文件,全部不一样种类的类型都被抽象成文件(好比:块设备,socket套接字,pipe队列)
二、操做这些不一样的类型就像操做文件同样,好比增删改查等
三、块设备支持随机访问,而字符设备只能依据前后顺序来读取数据。最典型的字符设备就是ttyhtml


2、环境准备

组件 版本
OS CentOS Linux release 7.5.1804


3、什么是tty?

根据史料记载:linux

An ASR33 Teletype - origin of the abbreviation tty.shell

tty来源一种电传打印机(teletype),就像这样:bash

● 敲击键盘输入不一样的字符,而后由打印机将字符打印在纸上
● 历史不断在往前发展,出现了计算机以后,计算机模拟了teletype的模式:经过外部终端输入,将输入的字符打印在屏幕上
● 在teletype与计算机之间用串口相连,而且在计算机上经过信号转换(模拟信号转换为数字信号),让计算机可以识别,从而操做计算机
● 因为计算机厂商众多,每一个厂商都有本身风格的输入设备,因此计算机为了兼容这些设备,开发了内核tty模块服务器

+-----------------+
                           |                 |
+--------+                 | +-------------+ |
|teletype|-----------------> |serial       | |
+--------+                 | |communication| |
                           | +-----+-------+ |
                           |       |         |
                           |       v         |
                           |  +----------+   |        +----------+
                           |  |tty driver|   |------->| display  |
                           |  +----------+   |        +----------+
                           |                 |
                           |computer         |
                           +-----------------+

4、tty设备文件

登录到操做系统(不使用SSH协议,而使用控制台直接登录),首先查看当前进程号所使用的tty网络

[root@localhost ~]# tty
/dev/tty1
[root@localhost ~]# ls -l /dev/tty1
crw--w---- 1 root tty 4, 1 Nov 20 23:24 /dev/tty1

当前所使用的是/dev/tty1,而且tty1也分配了主设备号与次设备号(关于主设备号与次设备号,请看以前的文章:块设备文件)ssh

查看进程打开的描述符socket

[root@localhost ~]# echo $$
5598
[root@localhost ~]# ls -l /proc/5598/fd
total 0
lrwx------ 1 root root 64 Nov 19 22:23 0 -> /dev/tty1
lrwx------ 1 root root 64 Nov 19 22:23 1 -> /dev/tty1
lrwx------ 1 root root 64 Nov 19 22:23 2 -> /dev/tty1
lrwx------ 1 root root 64 Nov 19 22:23 255 -> /dev/tty1

进程打开了4个文件描述符,这四个文件描述符都是/dev/tty1,他们的做用分别是:
0:标准输入
1:标准输出
2:标准错误
255:这个比较特殊,主要用于当tty重置的时候对0,1,2的一份复制(我的观点是对tty以前的历史信息做为一份复制)操作系统

更多的信息,请拜读大神的书《Shell Scripting: Expert Recipes for Linux, Bash, and more》,这里是连接(大概在267页):
https://doc.lagout.org/operating%20system%20/linux/Commands%20and%20Shell%20Programming/Shell%20Scripting.pdfunix


5、ssh登录以后的tty

刚才介绍的都是操做系统提供的控制台登录以后的状况,若是用ssh服务登录以后会产生什么状况呢?

首先介绍一个很是重要的概念,伪终端pty:
● pty是一对虚拟的字符设备,提供双向通讯。pty通常由master与slave组成
● pty的出现是为了知足如今的登录需求:网络登录(ssh登录、telnet登录等)、Xwindow等
● 历史上有两套接口标准:分别是BSD与unix98,当前大多数pts都是基于unix98标准来实现的
● unix98的工做流程:
(1)进程对/dev/ptmx调用open(),返回pseudoterminal master(PTM)的文件描述符,而且在/dev/pts下建立pseudoterminal slave(PTS): /dev/pts/0
(2)调用grantpt()修改PTS的文件权限;调用unlockpt()对PTS解锁;最后调用slavename()获得PTS文件名字
(3)此时,PTM与PTS都已经正常打开,而且创建一条通道,两端分别链接PTM与PTS
(4)进程对PTM写的数据能够从PTS读出来,反之亦然


下面重点介绍一下基于unix98实现的sshd pty(主要分为登录阶段和执行命令阶段):

登录:

(1)当进程ssh client请求与sshd创建登录链接的时候,通过TCP握手以及tls握手以后,确认是一个合法的请求,sshd会fork()一个子进程出来专门服务于这条链接

[root@localhost ~]# ps -ef | grep sshd
root       894     1  0 Nov25 ?        00:00:00 /usr/sbin/sshd -D
root      3126   894  0 Nov25 ?        00:00:00 sshd: root@pts/0

(2)子进程3126/dev/ptmx调用open(),获得PTM的文件描述符以及PTS的文件名

#这里使用strace跟踪sshd主进程和它建立的子进程,而后打开另一个shell登录服务器
[root@localhost ~]# strace -p 894 -ff -o sshd
strace: Process 894 attached
strace: Process 3126 attached
strace: Process 3127 attached
strace: Process 3128 attached
strace: Process 3129 attached
strace: Process 3130 attached
strace: Process 3131 attached
strace: Process 3132 attached
strace: Process 3133 attached
strace: Process 3134 attached
strace: Process 3135 attached
strace: Process 3136 attached
strace: Process 3137 attached
strace: Process 3138 attached
strace: Process 3139 attached
strace: Process 3140 attached
[root@localhost ~]# grep ptmx ./sshd.*
./sshd.3126:open("/dev/ptmx", O_RDWR)               = 8

sshd894建立了一个子进程3126用来处理这条TCP链接。进程对/dev/ptmx调用open(),获得PTM的文件描述符8

(2)子进程3126/dev/pts下建立了一个字符设备文件/dev/pts/08/dev/pts/0成为一对master/slave
(3)子进程3126会再fork()一个子进程3128,子进程3128打开/dev/pts/0 3个描述符(标准输入,标准输出,标准错误),而且执行操做系统默认的shell(本文中bash)

[root@localhost ~]# ps -ef | grep 3126
root      3126   894  0 03:16 ?        00:00:00 sshd: root@pts/0
root      3128  3126  0 03:16 pts/3    00:00:00 -bash
[root@localhost ~]# ls -l /proc/3128/fd
total 0
lrwx------ 1 root root 64 Nov 26 03:16 0 -> /dev/pts/0
lrwx------ 1 root root 64 Nov 26 03:16 1 -> /dev/pts/0
lrwx------ 1 root root 64 Nov 26 03:16 2 -> /dev/pts/0
lrwx------ 1 root root 64 Nov 26 03:22 255 -> /dev/pts/0

至此,通讯流程大概是这样:

+----------------+
+------------+           |                |
| ssh client +---------->|      sshd      |
+----+-------+           |                |
     |                   +--------+-------+
     |                            |
     |                            |
     |                         fork()
     |                            |
     |                            |
     |                            v
     |                       +----+-----+     fork()    +----------+      +-----+
     +---------------------->|pid: 3126 |-------------->|pid: 3128 |----->|bash |
                             +-+--------+               +----------+      +-----+
                               |                              ^
                               |                              |
                       +-------+                              |
                +------|--------------------------------+     |
                |      |                 +-----------+  |     |
                |      v                 |           |  |     |
                |  +---------+    fd=8   +-----------+  |     |
                |  |/dev/ptmx|---------->|/dev/pts/0 |--------+
                |  +---------+           +-----------+  |
                |                        |           |  |
                |                        +-----------+  |
                +---------------------------------------+

执行命令:

(4)当ssh client发出一个ls命令,经过TCP链接来到31263126ls写入PTM文件描述符8
(5)/dev/ptmx查询到关联记录 PTM:8对应PTS:/dev/pts/0,把ls转发到/dev/pts/0当中
(6)31280 -> /dev/pts/0中读取以后执行ls
(7)ls返回结果以后写入1 -> /dev/pts/0,而后根据关联记录回写到/dev/ptmx
(8)3126/dev/ptmx读取以后返回到ssh client


6、参考资料

http://man7.org/linux/man-pages/man7/pty.7.html
http://man7.org/linux/man-pages/man4/pts.4.html
http://osr600doc.sco.com/en/SDK_sysprog/_Pseudo-tty_Drivers_em_ptm_and_p.html
https://unix.stackexchange.com/questions/79334/how-does-a-linux-terminal-work



至此,本文结束 在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

相关文章
相关标签/搜索