天天看點

徹底了解Linux的各種終端類型以及概念

origin: http://blog.csdn.net/dog250/article/details/78766716

這篇文章的動機有兩個,上周同僚問我關于Linux終端的問題,我簡要解答後發現有些概念确實自己也說不清楚,然而這些概念我曾經是弄清楚了的,但也隻是曾經。

  大概六七年前,我是懂這些東西的,當時做了一些記錄:

linux終端閑談:http://blog.csdn.net/dog250/article/details/5692603

王然的煩惱–她很精通linux啦:http://blog.csdn.net/dog250/article/details/5692612

再談UNIX流機制和tty驅動:http://blog.csdn.net/dog250/article/details/5711036

printf的歸宿-資料列印到哪兒了:http://blog.csdn.net/dog250/article/details/23000909

塵封的那個記憶有點久遠,看了這些文章,我自己覺得有點不知所雲,除了最後一篇之外都很垃圾了…怎麼着?還是重新整理一下吧。如果一件事情自己都說不清楚,原因隻有一個,那就是這個人自己都沒有徹底了解它。

  重新寫這篇文章吧!感謝這位同僚,有了本文!

每天使用Linux每天都要接觸到Bash,使用Bash時似乎永遠都讓人摸不着頭腦的概念就是終端,坐在這台運作着Linux的機器的顯示器前面,這個顯示器就是終端的輸出,而插在機器上的USB鍵盤或者PS/2鍵盤就是終端的輸入,看來這是一種最直白意義上關于終端的解釋。

  但是有的時候,機器上并沒有看到顯示器或者鍵盤接口,但是卻有一個序列槽,想操作這台機器想必隻能通過這個序列槽來進行了,這個時候,序列槽另一端的那台電腦的顯示器鍵盤也叫做終端。除了上述兩種意義的終端之外,我們使用的類似SecureCRT這種軟體上運作的SSH,Telnet等也算是一種終端程式,隻是說它是通過TCP/IP網絡而不是通過序列槽與主機連接配接的。

  現在可以給終端下一個非嚴格意義上的定義了,什麼是終端?終端就是處理計算機主機輸入輸出的一套裝置,它用來顯示主機運算的輸出,并且接受主機要求的輸入,典型的終端包括顯示器鍵盤套件,列印機打字機套件等。但想要徹底了解終端的概念,還是要從計算機發展曆史的角度去尋根溯源。

  最開始的時候,計算機有三間房屋那麼大,确切地講應該叫三間工廠中的房間。如此的龐然大物有一個專門的操作台,就好像機床廠工廠中的房間的操作台一樣,或者說它像飛機駕駛艙的操作台更加合适,各種儀器儀表,操作員隻需要在這裡對這部機器發出指令,整部機器就開始為他的指令而運算,然後機器運算後的結果也會回報到這裡而不是其它地方,這裡這個操作台就是最原始的終端。這裡曾經是整部機器的控制中樞。

徹底了解Linux的各種終端類型以及概念

後來有了多使用者多任務分時系統,不同的程式竟然可以“同時運作”了,為了讓不同的程式分别獨立地接受輸入和處理輸出,就需要多個不同的上述的操作台,當然了,坐在或者站在操作台前面的最好始終是同一個人,這樣不同的人擁有不同的操作台處理不同的程式,這就進入了多終端時代,從這時起一直到現在,每一個終端都是和一個使用者綁定的。為了保證這種綁定,于是就出現了登入,即通過一種叫做登入的動作,去喚起一個終端起來工作。為了支援多使用者,終端從硬體分離了出來,終端成了一個軟體概念,在一個硬體終端上成功登入後,便獲得了一個軟體終端。

  可見,這個時代已經和三工廠中的房間的時代不同了,終端不再隻有一個,而是變成了多個,每一個登入成功的使用者擁有一個可工作的軟體終端來處理輸入輸出。

徹底了解Linux的各種終端類型以及概念

分久必合。

  到了個人計算機時代,計算機和終端又成了一對一的關系。畢竟嘛,這時的計算機叫做個人計算機,并不是随便誰都能用的,計算機本身就是歸屬個人,是以根本沒必要去支援什麼多使用者,或者至少是淡化了多使用者和多終端的概念。我們都曾記得,當時買電腦的時候,都是一個主機配一個顯示器和一套鍵盤滑鼠,這種情況從上世紀80年代初一直持續到今天。不過近些年來當人們逐漸全面認識到計算機和終端的一對一關系後,一體機的市場就來了,既然你幾乎不會(我當然知道有人會,但這裡我說的是大多數人,程式員占比寥寥,程式員為了裝X,是不會用一體機的,就連品牌機套裝有時也不屑的)在同一主機上接多個顯示器多套鍵盤,何必再那麼麻煩,幹脆把主機和顯示器合在一起不就好了嘛。嗯,這個點子不錯,循着這個路子,最終有了觸屏一體機,連鍵盤都内置了。對比一下下圖和三工廠中的房間裡的計算機時代,是不是很像呢?

徹底了解Linux的各種終端類型以及概念

但是好景不長。

  合久必分。

  一切似乎又回到了大型機時代。在大型機時代,一台機器是擁有多個終端的,那是五十年以前。今天,我們擁有了各種各樣的小型裝置,智能手機,平闆電腦,智能手表….然而這些東西,其實僅僅隻是一系列的終端而已!那麼既然這些東西都成了終端,真正的計算機在哪兒?當然在各大機房(也是類似工廠中的房間大小的那種房間)裡了,隻是現在不叫大型機了,而叫做雲端,這種技術叫做雲計算(似乎有點炒作概念的意思)。如果你不信你花了幾千上萬塊的錢買來的裝置僅僅是一個完成輸入輸出功能的終端,那麼請斷網試試,看看你的iPhone是不是變磚頭了。可見,昂貴的是雲提供的計算服務,而不是終端裝置本身,我們把所謂的雲看作是一台計算機,這幅圖景是不是跟五十年前的非常像呢?

徹底了解Linux的各種終端類型以及概念

你有多久沒有打開過家裡的PC了,是不是很久了,但是日子也還過得去。但是你能忍受哪怕幾個小時不登入微信嗎?某種意義上,成為新的終端的不是這些個硬體裝置,而是基于雲計算技術的現代網際網路服務的各類APP。

  是不是又要分久必合了呢?早就有迹象了,從用QQ号可以登入微信,微網誌,内推網的時候就有迹象了。

好了,扯了這麼多關于終端的發展,其實根本上也就一句話,能接受輸入,能顯示輸出,就這就夠了,不管到了什麼時代,終端始終扮演着人機接口的角色,所謂Terminal,即機器的邊緣!

  隻要能提供給計算機輸入和輸出功能,它就是終端,而與其所在的位置無關。我可以用ls指令列舉五千公裡以外的一台計算機上某個目錄下的檔案并且顯示在我眼前的螢幕上,至于我的輸入如何到達五千公裡以外,這并不是我要關注的,也不是計算機要關注的,這顯然隻是一個通信方式問題。那麼使用TCP/IP網絡進行這類通信傳輸就是再顯然不過的了。

  這就是SSH使用的方法。我們知道,SSH是一個TCP/IP協定族的協定,而其上跑的卻是一個遠端登入後的終端流,這顯然隻是用TCP/IP建構了一條隧道,然後終端流通行于該隧道。除此之外,更簡單的Telnet也不例外,也是通過一個TCP/IP隧道來封裝承載遠端登入的終端流。除卻TCP/IP,如果我們執意使用卡車來運載我們的輸入和輸出,也完全是合适的,TCP/IP也好,卡車也好,它們隻是通信手段,它們并非終端本身。

我們現在可以想象一下終端存在的形式都會有哪些。

  • 本地終端

    用VGA連接配接主機和顯示器,用PS/2或者USB連接配接主機和鍵盤,這樣的一個顯示器/鍵盤組合就是一個本地終端。

  • 用序列槽連接配接的遠端終端

    通過序列槽線把主機接到另外一個有顯示器和鍵盤的主機,通過運作一個終端模拟程式,比如“Windows超級終端”來将這台主機的顯示器和鍵盤借給序列槽對端的主機。

  • 用TCP/IP承載的遠端終端

    類似Telnet,SSH這般。

大緻就先說這幾類吧。可見上述的三類中,前兩類都是在本地就直接關聯了實體裝置的,比如VGA口啊,PS/2口啊,序列槽啊之類的,這種終端叫做實體終端,而第三類在本地則沒有關聯任何實體裝置,注意,不要把實體網卡當成終端關聯的實體裝置,它隻是隧道關聯的實體裝置,這裡的實體網卡完全可以換成卡車,它們與終端并不直接相關,是以這類不直接關聯實體裝置的終端叫做僞終端。

  既然知道了這些終端到底是怎麼回事,了解餘下來的那些術語就不在話下了。這些術語的存在并非是為了故意增加複雜性,而是因為工程上的東西必須要有可操作性,要可操作就必須至少有個名字來稱呼,僅此而已。這跟我們中國的傳統道,可道非常道;名,可名非常名是完全不同的。可謂現代數學,既要有名又要有道,而現代工程,則必須舍道而取名。

  先看下Linux系統中管終端都叫做什麼。

tty是最令人熟悉的了,在Linux中,/dev/ttyX代表的都是上述的實體終端,其中,/dev/tty1~/dev/tty63代表的是本地終端,也就是接到本機的鍵盤顯示器可以操作的終端。換句話說,你往/dev/tty3裡寫個東西,它就會顯示在顯示器對應的終端。

  為什麼會有63個終端這麼多呢?畢竟顯示器隻是一個單獨的顯示裝置,鍵盤往往也隻有一個,但Linux核心有能力知道現在該幹什麼,是以事實上Linux核心在初始化時會生成63個本地終端,通過鍵盤上的Fn-Alt-FX(X為1,2,3…)可以在這些終端之間切換,每切換到一個終端,該終端就是目前的焦點終端,比如說,你按下了Fn-Alt-F4組合鍵,那麼此時第4個終端就是焦點終端,即/dev/tty4就是焦點終端裝置。

徹底了解Linux的各種終端類型以及概念

誰是焦點終端會被核心記錄為全局變量,這樣隻要有鍵盤輸入,就會把輸入的字元交給焦點終端。這裡順便提一下,對于序列槽而言,不存在焦點終端的概念,誰連了序列槽就是誰,而對于僞終端來講,一般情況下client都是運作在GUI環境,對于Windows那是微軟的事,對于Linux,則有X系統完成同樣的事,在此略過,繼續我們正在說的話題。

  系統中有沒有什麼變量可以表示焦點終端呢?當然有了,那就是/dev/console,不管你在哪裡往/dev/console裡寫東西,這些東西總會出現在系統目前的焦點終端上!

  按照以他人為中心,我們解釋了/dev/console其實就是一個全局變量,指代目前的焦點終端,如果目前的焦點是/dev/tty4,那麼/dev/console指的就是/dev/tty4,當然這一切都是由核心來維護的。

  那麼系統中有沒有一個叫做自己的全局變量呢?當然有,那就是/dev/tty,也就是說,無論你在哪個終端下工作,當你往/dev/tty裡寫東西的時候,它總是會馬上出現在你的眼前。

  /dev/tty1~/dev/tty63我們知道了它們是什麼,/dev/tty表示自己,/dev/console表示焦點終端這些我們也知道了,那麼序列槽終端如何表示呢?很簡單,以ttyS

開頭的就是序列槽連接配接的終端,比如ttyS1,ttyS2…

  最後,解釋一下僞終端。其實也很好解釋,隻要你了解TUN/TAP虛拟網卡的原理就行,它們如出一轍!類似Telnet,SSH不是沒有實際的實體裝置嗎?簡單,給它模拟一個不就得了?系統是分層的,執行流隻管調用接口,并不管具體實作。

  模拟一個虛拟的終端裝置,實作它的write,read等回調即可。對于VGA連接配接的顯示器而言,write其實就是将顯存重新整理,而對于僞終端而言,write其實是想将資料導入到一個使用者态的程式中(不然又能去哪裡呢?它下面又沒有任何實體的東西),這簡直跟很多VPN的原理非常類似。為此,Linux設計出一對虛拟終端裝置,即/dev/ptmx和/dev/pts/X,這就跟TUN/TAP網卡的網卡與字元裝置之前的對應關系一緻。

  簡單來講,當有ssh用戶端連接配接後,sshd會fork一個程序,然後在子程序中打開一個叫做/dev/pts/1(或者2,3,4,5…)的裝置,然後和sshd程序的/dev/ptmx配對,這樣在ptmx與pts之間就構成了一條管道,資料可以順利被導入到sshd,然後通過TCP/IP封裝發往ssh client所在的機器。

  為了幫助了解上述的文字,我特意作圖一張,希望能解釋清楚這些終端之間的關系以及弄明白它們的工作流程。為了讓圖畫的更加緊湊,避免橫向網絡吧圖拉的過長而不好看,我這裡采用了環形解釋法,類似Intel早先的Ring1,Ring2,Ring3,我把最内層視作硬體(比它更裡面的還有叫做人的東西),中間層視作核心,最外層視作軟體。

徹底了解Linux的各種終端類型以及概念

了解了圖例,我上我的圖,這是我昨晚畫到很晚才完成的,希望能有寶貴的意見提出(圖有點大,請單獨檢視):

徹底了解Linux的各種終端類型以及概念

/dev目錄下的各種tty,ptmx,pts/X,console等等這些是令人混淆的根源,其實了解這些是有竅門的,記住它們隻是操作某種終端裝置的裝置檔案而已,這是UNIX風格的延續,這些裝置檔案對應的真實裝置也就那麼幾種,比如顯示器鍵盤套件,序列槽對面的超級終端,僞終端對面的SSH,Telnet等等。然後試着畫出一個上面的圖,基本就理清楚了。

本文的最後,我來簡單說下關于getty和login相關的東西。

  前面在講終端發展曆史的時候說到過,到了多終端時代,每一個終端必須綁定一個使用者,隻有登入成功的使用者方可獲得一個終端。是以當一個人站到一個終端面前并不意味着它就能在這個終端上操作計算機,他首先要做的就是登入。所謂的登入呢,就是輸入使用者名和密碼,如果輸入正确,則會給你一個Bash(或者别的Shell)讓你操作計算機,如果輸入不正确,則讓你繼續輸入…

  getty給了讓你登入并且繼續輸入的機會!init程序不斷調用getty,然後getty會發起login讓你登入,當你輸入正确的使用者名和密碼後,ttyXYZ就是你的了,如果你是用SSH進行的login,那麼你将得到一個叫做/dev/pts/X,如果你是在顯示器鍵盤登入,你将得到/dev/tttX(X取決于目前的焦點終端)。

  所有這一切其實都是多終端以及多使用者的産物,但歸根結底其根源都在分時系統。在計算機最初被放在工廠中的房間大小的屋子裡的年代,可能把屋子的門禁做好以及将屋子外的鑒權系統做好顯得比後來的多使用者login更為重要,隻有在後來,終端不再屬于計算機了,終端與計算機分離了,使用者也和終端分離了的時候,設計一套登入機制就顯得尤為必要了,因為首先即便你把計算機鎖在鐵屋子裡,隻要終端在外面,那麼計算機就毫無安全感可言,其次,你也不可能把終端全部鎖在完全屬于你控制的鐵屋子裡,特别是在TCP/IP出現以後,幾乎所有的計算機都是互聯互通的,這意味着任何一台計算機都可以作為其它任何一台另外的計算機的操作終端,任何外部的鑒權系統和實體保護在TCP/IP網絡面前都堪比馬其諾防線,看似固若金湯,實則百無一用。

寫完了,最後說一點題外話。

  如果想檢驗一下自己是否多一件事情有足夠深刻的了解,那麼試着給别人講一講,試着回答别人不斷深入的問題,迎接挑戰,這是正道。

  這就是一直以來我總喜歡強行給别人扯希臘羅馬文化的原因,意在反駁大多數人認為的東方文化更優秀的現實。我并不意味着我不是愛國主義者,這隻是一種思維遊戲。但久而久之,随着了解不斷深刻,我自己竟然也成了一個歐洲中心主義者。

  我的本意是想解釋中國的傳統文化和歐洲的文化有什麼本質上的不同,最終肯定不是陷入歐洲中心主義,就是陷入中華中心主義的華夏秩序,然而我上當了,我發現這種刻意把兩種文化區分開來做PK狀的論調本身就是陷入了徹頭徹尾的歐洲中心主義,這難道不是源自于一神教的排他性在作怪嗎?

  然而反過來,我既然認識到了這一點,說明我内心深處還是有自省機制的,這種自省機制難道不是來自中華的傳統嗎?我們知道,歐洲猛在外取諸物,中華則強在内省其身。

  最近在看梁漱溟的書,雖然很多人批判他,但我還是能從他的書裡學到了很多的東西。也算是讀後感吧,就着和同僚讨論關于終端的遺留問題的解答以及對梁漱溟學問的感想,寫下了最後這幾段文字。

—————-關于行規程的補遺—————–

說了這麼多,竟然沒有詳細寫關于行規程的内容,也算遺憾,于是準備另起一篇文章來單獨讨論。

繼續閱讀