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



至此,本文結束 在下才疏學淺,有撒湯漏水的,請各位不吝賜教...

相關文章
相關標籤/搜索