終端是一種輸入輸出設備。把終端連接到計算機上,就可以跟計算機進行交互。當今個人電腦最常用的兩種終端設備分別是作為輸入終端的鍵盤以及作為輸出終端的顯示器。
各種概念的關系
在 Windows 上的 CMD、 Powershell、 XShell 或者 PuTTY 被稱為終端模擬器(Terminal Emulator)。
使用終端模擬器登錄到 Linux 時,使用的是偽終端(PTY,Pseudo TTY)。
偽終端分為主和從兩個部分,與終端模擬器交互的部分是主(PTM,Pseudo TTY Master),與用戶進程交互的部分是從(PTS,Pseudo TTY Master)。
與機器相連接的終端設備,被稱為遠程打字機(TTY,TeleTYpewriter)。
在 Linux 操作系統里面,物理設備被對應到 TTY 串口(TTYS,TTY Serial)上。將一套物理的終端設備模擬為多套終端設備,在系統里面表示為 TTY。
電報機
圖 1:電報機
電報是一種最早用電的方式來傳送信息的、可靠的即時遠距離通信方式。
1837 年發展出了電報機以及電報系統[1]。電報機的發送設備只有一個發報按鍵(如圖 1 所示),通過短按表示短信號(“.” 滴)和長按表示長信號(“-” 嗒)。發送方按下按鍵后,信號會立馬發送出去,接收方很快就能收到消息。
將長短信號按照一定順序排列得到不同的組合,這些組合可以各自對應一種信息,這些對應關系的對應表稱為電碼。最出名的電碼是摩爾斯電碼。
圖 2:摩爾斯電碼表
有興趣的話,可以聽聽看:
三分鍾教你學會摩爾斯電碼
https://www.bilibili.com/video/BV1Hk4y1y7RH
國際通用求救信號是 SOS,S 由三個“滴”表示,O 由三個“嗒”表示,則 SOS 的摩爾斯電碼為 ...---...
(滴滴滴 嗒嗒嗒 滴滴滴) 。
電碼只有包括滴、嗒、停頓等少數信息,因此需要發送者先 人為地 將字母轉換為電碼(編碼),接收者再 人為地 將電碼轉換為字母(解碼)。接收者需要帶上耳機聽電報音。
我們希望能有設備代替收發雙方做編碼和解碼的工作,直接與 abcd 這種字母交互。於是找上了打字機。
機械打字機(typewriter)
第一台商業化的機械打字機出現於 1874 年[2]。打字機主要由鍵盤、印字機組成。鍵盤提供了更多地按鍵,包括了 26 個字母、數字和其他一些按鍵。
圖 3:機械打字機
機械打字機通過機械的轉動將字母打在紙上。如果你有看過《紫羅蘭永恆花園》,女主的工作就是使用機械打字機幫別人寫信。比如下面這個視頻里的:
【開箱】我把京紫女主用的打字機給買回了家
https://www.bilibili.com/video/BV18W411v7x9
你會發現看到的打字機的鍵盤布局是 QWERT 布局。現在 QWERT 的鍵盤布局實際上是繼承於機械式打字機。機械打字機使用 QWERT 布局是因為如果在機械式打字機上打字太快會發生卡殼,而這種布局能減緩使用者的打字速度。
如果看了打字機的使用過程,你就能知道現代換行用
\r\n
表示的含義了。
\r
表示 carriage return。carriage 的英文釋義為 “A moving part of a machine that carries other parts into the required position”[3]。因此 carriage return 是讓打字機印字時移動的那塊返回到行首。
接着由表示 Newline 的\n
讓印字機旋轉到下一行。\n
也稱為 line feed。
因此文本編輯器里的 CRLF 是 carriage return + line feed 的縮寫,表示\r\n
。
從機械打字機的使用者的角度看,按下字母 a 的按鍵后紙條上就顯示 a,不需要使用者做編碼和解碼工作。這正好做電報機的編碼解碼器,只需要設計一個轉換器,將字母按鍵的機械轉換為對電報機的操作就行了。
圖 4:打字機、摩爾斯電報機發送器、電傳打字機
電傳打字機(teletypewriter,teleprinter)
圖 5:電傳打字機
首次用於發送電報的電傳打字機出現於 1887 年[4]。它主要由鍵盤、印字機和收發報機等組成。看起來是打字機 + 電報機的組合對吧?
感受一下電傳打字機的運行:
[轉載]在30多年前的電傳打字機上聊天是怎樣一種體驗?
https://www.bilibili.com/video/BV1Xx41137Tp
電傳打字機將信號通過收發報機發送出去。上面那個視頻 04:04 時間點,能聽到電報機的聲音。雖然電傳打字機也是用電報機,但它通常使用五單位電碼(博多電碼),而不是長短不一的摩爾斯電碼。
電傳打字機傳送方式有兩種:
- 一種可以看作電報的改進版,即連接的雙方有一方按下按鍵時,會把電碼立即傳送到另一方的印字機上;
- 另一種用打字機把消息信號以在穿孔紙帶[5]上鑿孔,再把紙帶放到發報器上發報(如圖 5)。
下面這個視頻就是第二種方式的演示:
Teletype Model 35ASR 電傳打字機
https://www.bilibili.com/video/BV1Gt411B7Xf
如果只將電傳打字機看作電報的改進版,你會發現少了個東西:看不到已經打了什么字。不過打字機自身有帶打印功能,可以讓打字機在收發報時將字打印在紙上。這個步驟稱為“回顯”。
由於電傳打字機沒有緩沖,如果發送方太快,接收方可能來不及打印。於是發送方允許接收方回傳兩個控制信號,一個告訴發送方停止發送,一個告訴發送方繼續發送。現在這兩個特性仍然被終端模擬器保留,快捷鍵分別是 ctrl + s
和 ctrl + q
。這就是有時候按錯按鍵發現終端模擬器“卡住了”的原因[6]。
隨着技術的發展,計算機出現了。
把電傳打字機改造為計算機的終端
圖 6:把電傳打字機改造為計算機的終端
第一台計算機在 1946 年問世,但它是通過操作按鈕來控制。不過后來的大型機發展到包含了控制台、終端和主機。控制台用於管理設備的硬件,終端則用於和計算機交互。這個時候現代鍵盤還沒出現,用到的終端是從電傳打字機改造而來的,而且和整台機器組合在一起。
圖 7:Ken & Den
現在也可以把電傳打字機接到電腦上作為輸入終端和顯示終端,只是需要調制解調器(modem,貓)連接到收發報機:
用電傳打字機作為 Linux 的顯示終端
https://www.bilibili.com/video/BV1aK4y187yp
前面說過,計算機包含了控制台和終端,這兩者在現在似乎沒有區別,但以前是有區別的。如下圖:
圖 8:控制台和終端[9]
多終端
計算機數量少,運行的費用高,且一個終端未必能完全利用 CPU 資源。於是出現了分時操作系統,允許有多個終端,且可以是遠程終端。這樣可以在只有一台終端設備連接到計算機的情況下,模擬出有多套終端設備連接的樣子。同時也可以讓其他人付費通過遠程使用多出來的終端。
在本地接多個終端的圖片不好找,不確定下面這篇文章里的圖片算不算:
圖 9:IBM System/390 [10]
硬件的部分就到這里,接下來是跟 Linux 操作系統相關的內容。
串行終端 ttyS (ls /dev/ttyS*)
Linux 系統里面有表示接入的硬件設備的文件,用 ls /dev/ttyS*
查看。這些文件與計算機的串口(serial port)對應。
終端 tty (ls /dev/tty) 和控制台 console (ls /dev/console)
在大型機時代,終端和控制台是分開的,分別表示一台物理設備,但現在兩者的界線沒有那么清晰。
tty 在經過模擬后得到多個虛擬設備,統稱為虛擬終端,就好像有多套物理的輸入輸出設備,而 console 只有一個。
通過 ls /dev/tty[0-9]*
可以看到所有虛擬終端,將這個集合表示為 ttyN,其中 N 表示數字。用 ctrl + alt
加上 F1
~ F6
其中一個快捷鍵來切換到 tty1 ~ tty6。執行 tty
會顯示當前所在 tty。
注:如果通過類似 XShell 的終端模擬器遠程連接,得到的結果與上述不同。到偽終端的部分就知道為什么了。
你會發現少了 tty0。/dev/tty0
和 /dev/console
的行為類似,都是表示當前終端,但只允許操作系統和 root 用戶寫入數據。而對於普通用戶,/dev/tty
這個文件就是表示當前終端,且當前用戶可以寫入數據。
如何使用“當前終端文件”?可以試試執行 echo "test" > /dev/tty
。你會發現屏幕輸出了 test。如果執行 tty
得到的是 /dev/tty3
,那么執行 echo "test" > /dev/tty3
將得到相同結果。/dev/tty
是 /dev/tty3
的別名。
Linux 是多用戶操作系統,可以切換到不同的終端登錄不同的用戶。執行 ls -l /dev/tty[0-9]*
能查看各終端的擁有者。例如執行 ls -l /dev/tty3
可以看到:
crw--w---- 1 schaepher tty 4, 3 Feb 24 12:20 /dev/tty3
這表示 schaepher 這個用戶持有 /dev/tty3
這個設備。
到目前為止,仍然是使用文本終端,並且在虛擬出的多套輸入輸出設備中選擇。通俗地說,一個屏幕同一時刻只能展示其中一個終端的輸出。在有圖形界面后,出現了如何在圖形界面里使用文本終端的問題。也就是想讓輸出到某個設備的內容單獨地展示在屏幕的某一塊區域,以及聚焦到這塊區域后,可以輸入內容到設備。
我們希望在圖形界面里單獨創建一個進程,讓它在屏幕的一塊區域內作為文本終端運行,於是這個進程就作為一個終端模擬器來使用了。
說到終端模擬器,上述的虛擬終端就是經過模擬多套設備后得到的。不過問題是圖形界面運行在用戶空間,而終端模擬器運行在內核空間。我們需要將終端模擬器移動到用戶空間,但同時又要避免用戶空間繞過內核直接操作設備。
於是偽終端 pseudo tty 被發明出來解決這個問題。
偽終端 pty (ls /dev/pts/*)
偽終端被分為主(master)從(slave)兩個部分。pty slave 用於模擬硬件文本終端設備,pty master 提供了一套終端模擬器進程控制 pty slave 的方法。
終端模擬器運行於用戶空間,與 pty master 交互,pty master 再通過 LDISC 與 pty slave 交互,pty slave 再與用戶進程交互。
例如登錄到 Linux 圖形界面后打開終端窗口執行 tty,可以得到 /dev/pts/0
。或者使用 ssh 登錄到遠程服務器執行 tty,也會得到 /dev/pts/某個數字
。這里的 pts 指的是 pty slave。
執行 ls -l /dev/pts/
能看到都有哪些用戶使用了 pty。
參考
[1]: https://en.wanweibaike.com/wiki-Electrical_telegraph (Electrical telegraph)
[2]: https://en.wanweibaike.com/wiki-Typewriter (Typewriter)
[3]: https://www.lexico.com/search?utf8=%E2%9C%93&filter=en_dictionary&dictionary=en&s=t&query=carriage (carriage)
[4]: https://site.xavier.edu/polt/typewriters/tw-history.html (A Brief History of Typewriters)
[5]: https://www.ccf.org.cn/Computing_history/Updates/2020-09-10/720617.shtml (我的計算機收藏之旅(9):你見過或沒有見過的存儲器)
[6]: https://unix.stackexchange.com/questions/137842/what-is-the-point-of-ctrl-s/137846#137846 (What is the point of Ctrl-S?)
[7]: https://www.bell-labs.com/usr/dmr/www/picture.html (An amusing photo)
[8]: https://www.zhihu.com/question/59318669/answer/164408260 (為何 Linux 的系統 API 相比 Win32 到處是縮寫?有何優劣? 造成兩者差別的原因是什么?)
[9]: https://www.cnblogs.com/pluse/p/6897830.html (關於Unix/Linux的終端、偽終端、控制台和shell)
[10]: https://servers.pconline.com.cn/gc/1202/2679853_5.html (人類登月不可或缺 大型機半個世紀發展史)
其他:
Linux 終端(TTY)
https://blog.csdn.net/smilefxx/article/details/102766993
Pseudo TTY
https://en.wanweibaike.com/wiki-Pseudo TTY
The TTY demystified
http://www.linusakesson.net/programming/tty
Linux TTY/PTS概述
https://segmentfault.com/a/1190000009082089
掃盲 Linux&UNIX 命令行——從“電傳打字機”聊到“shell 腳本編程”
https://blog.csdn.net/JunSIrhl/article/details/104374649