雖然一直做嵌入式Linux,宿主機和開發板通信天天都在用tty設備通信,但是其實自己對TTY設備及終端的概念認識幾乎是0。對於Linux內核的終端、tty、控制檯等概念的認識很模糊。由於在學習的時候碰到了重定向console的問題,所以藉機學習下tty的知識。以下是我對tty的認識總結,信息來源於網絡和內核文檔。參考資料見文章末尾。
tty一詞源於Teletypes,或Teletypewriters,它是最早出現的一種終端設備,類似電傳打字機,由Teletype公司生產。最初tty是指連接到Unix系統上的物理或者虛擬終端。終端是一種字符型設備,通常使用tty來統稱各種類型的終端設備。隨着時間的推移,當通過串行口能夠建立起終端連接後,這個名字也用來指任何的串口設備。它還有多種類,例如串口(ttySn、ttySACn、ttyOn)、USB到串口的轉換器(ttyUSBn),還有需要特殊處理才能正常工作的調制解調器(比如傳統的WinModem類設備)等。tty虛擬設備支持虛擬控制檯,它能通過鍵盤及網絡連接或者通過xterm會話登錄到計算機上。
- 其實起初終端和控制檯都不是個人電腦的概念,而是多人共用的小型中型大型計算機上的概念。
- 終端爲主機提供了人機接口,每個人都通過終端使用主機的資源。終端有字符終端和圖形終端兩種。一臺主機可以連很多終端。
- 控制檯是一種特殊的人機接口, 是人控制主機的第一人機接口。而主機對於控制檯的信任度高於其他終端。
- 而個人計算機只有控制檯,沒有終端。當然願意的話,可以在串口上連一兩臺字符啞終端。但是linux按POSIX標準把個人計算機當成小型機來用,在控制檯上通過getty軟件虛擬了六個字符啞終端(或者叫虛擬控制檯終端tty1-tty6)(數量可以在/etc/inittab裏自己調整)和一個圖型終端, 在虛擬圖形終端中又可以通過軟件(如rxvt)再虛擬無限多個僞終端(pts/0等)。但這全是虛擬的,雖然用起來一樣,但實際上沒有物理實體。所以在個人計算機上,只有一個實際的控制檯,沒有終端,所有終端都是在控制檯上用軟件模擬的。要把個人計算機當主機再通過串口或網卡外連真正的物理終端也可以,論成本,誰會怎麼做呢。
終端按照其自身能力分類,可以分爲:
1、啞終端(瘦客戶端)
早期的計算機終端是通過串行RS-232通信的,它只能解釋有限數量的控制碼(CR,LF等),但沒有能力處理執行特殊的轉義序列功能(如清行、清屏或控制光標的位置)。簡單來說就是處理能力有限的終端機,他們一般基本上只具有和機械電傳打字機類似的有限功能。這種類型的終端稱爲啞終端。現在仍然在現代類Unix系統上得到支持,通過設置環境變量TERM=dumb。啞終端有時用來指任何類型的通過RS-232連接的傳統計算機終端,不對數據進行本地處理或本地執行用戶程序的串行通信終端。啞終端有時也指功能有限,只有單色文本處理能力或直接傳輸每一個鍵入的字符而不等待主機輪詢的公共計算機終端。
2、智能終端(胖客戶端)
智能終端就是有能力處理轉義序列,也就是說處理能力較強的終端機。
Linux系統的終端設備一般有以下幾種:
- 1、 控制檯
- 系統控制檯/dev/console
/dev/console是系統控制檯,是與操作系統交互的設備。系統所產生的信息會發送到該設備上。平時我們看到的PC只有一個屏幕和鍵盤,它其實就是控制檯。目前只有在單用戶模式下,才允許用戶登錄控制檯/dev/console。(可以在單用戶模式下輸入tty命令進行確認)。
console有緩衝的概念,爲內核提供打印輸出。內核把要打印的內容裝入緩衝區__log_buff,然後由console來決定打印到哪裏(比如是tty0還是ttySn等)。console指向激活的終端。歷史上,console指主機本身的屏幕和鍵盤,而tty指用電纜鏈接的其它位置的控制檯。某些情況下console和tty0是一致的,就是當前所使用的是虛擬終端,也是激活虛擬終端。所以有些資料中稱/dev/console是到/dev/tty0的符號鏈接,但是這樣說現在看來是不對的:根據內核文檔,在2.1.71之前,/dev/console根據不同系統設定,符號鏈接到/dev/tty0或者其他tty*上,在2.1.71版本之後則完全由內核代碼內部控制它的映射。
如果一個終端設備要實現console功能,必須向內核註冊一個struct console結構,一般的串口驅動中都會有。如果設備要實現tty功能,必須要內核的tty子系統註冊一個struct tty_driver結構,註冊函數在drivers/tty/tty_io.c中。一個設備可以同時實現console和tty_driver,一般串口都這麼做。
- 當前控制檯: /dev/tty
這是應用程序中的概念,如果當前進程有控制終端(Controlling Terminal),那麼/dev/tty就是當前進程控制檯的設備文件。對於你登錄的shell,/dev/tty就是你使用的控制檯,設備號是(5,0)。不過它並不指任何物理意義上的控制檯,/dev/tty會映射到當前設備(使用命令“tty”可以查看它具體對應哪個實際物理控制檯設備)。輸出到/dev/tty的內容只會顯示在當前工作終端上(無論是登錄在ttyn中還是pty中)。你如果在控制檯界面下(即字符界面下)那麼dev/tty就是映射到dev/tty1-6之間的一個(取決於你當前的控制檯號),但是如果你現在是在圖形界面(Xwindows),那麼你會發現現在的/dev/tty映射到的是/dev/pts的僞終端上。/dev/tty有些類似於到實際所使用終端設備的一個聯接。
你可以輸入命令 “tty",將顯示當前映射終端如:/dev/tty1或者/dev/pts/0等。也可以使用命令“ps -ax”來查看其他進程與哪個控制終端相連。
在當前終端中輸入 echo “tekkaman” > /dev/tty ,都會直接顯示在當前的終端中。
- 虛擬控制檯 /dev/ttyn
/dev/ttyn是進程虛擬控制檯,他們共享同一個真實的物理控制檯。
如果在進程裏打開一個這樣的文件且該文件不是其他進程的控制檯時,那該文件就是這個進程的控制檯。進程printf數據會輸出到這裏。在PC上,用戶可以使用alt+Fn切換控制檯,看起來感覺存在多個屏幕,這種虛擬控制檯對應tty1~n,其中 :
/dev/tty1等代表第一個虛擬控制檯
例如當使用ALT+F2進行切換時,系統的虛擬控制檯爲/dev/tty2 ,當前控制檯(/dev/tty)則指向/dev/tty2
在UNIX系統中,計算機顯示器通常被稱爲控制檯(Console)。它仿真了類型爲Linux的一種終端,並且有一些設備特殊文件與之相關聯:tty0、tty1、tty2等。當你在控制檯上登錄時,使用的是tty1。使用Alt+[F1—F6]組合鍵時,我們就可以切換到tty2、tty3等上面去。
你可以登錄到不同的虛擬控制檯上去,因而可以讓系統同時有幾個不同的會話存在。
而比較特殊的是/dev/tty0,他代表當前虛擬控制檯,是當前所使用虛擬控制檯的一個別名。因此不管當前正在使用哪個虛擬控制檯(注意:這裏是虛擬控制檯,不包括僞終端),系統信息都會發送到/dev/tty0上。只有系統或超級用戶root可以向/dev/tty0進行寫操作。tty0是系統自動打開的,但不用於用戶登錄。在Framebuffer設備沒有啓用的系統中,可以使用/dev/tty0訪問顯卡。
- 2、 僞終端pty(pseudo-tty)
僞終端(Pseudo Terminal)是終端的發展,爲滿足現在需求(比如網絡登陸、xwindow窗口的管理)。它是成對出現的邏輯終端設備(即master和slave設備, 對master的操作會反映到slave上)。它多用於模擬終端程序,是遠程登陸(telnet、ssh、xterm等)後創建的控制檯設備。
歷史上,有兩套僞終端軟件接口:BSD接口:較簡單,master爲/dev/pty[p-za-e][0-9a-f] ;slave爲 /dev/tty[p-za-e][0-9a-f] ,它們都是配對的出現的。例如/dev/ptyp3和/dev/ttyp3。但由於在編程時要找到一個合適的終端需要逐個嘗試,所以逐漸被放棄。Unix 98接口:使用一個/dev/ptmx作爲master設備,在每次打開操作時會得到一個master設備fd,並在/dev/pts/目錄下得到一個slave設備(如 /dev/pts/3和/dev/ptmx),這樣就避免了逐個嘗試的麻煩。由於可能有好幾千個用戶登陸,所以/dev/pts/*是動態生成的,不象其他設備文件是構建系統時就已經產生的硬盤節點(如果未使用devfs、udev、mdev等) 。第一個用戶登陸,設備文件爲/dev/pts/0,第二個爲/dev/pts/1,以此類推。它們並不與實際物理設備直接相關。現在大多數系統是通過此接口實現pty。
我們在X Window下打開的終端或使用telnet 或ssh等方式登錄Linux主機,此時均通過pty設備。例如,如果某人在網上使用telnet程序連接到你的計算機上,則telnet程序就可能會打開/dev/ptmx設備獲取一個fd。此時一個getty程序就應該運行在對應的/dev/pts/*上。當telnet從遠端獲取了一個字符時,該字符就會通過ptmx、pts/*傳遞給 getty程序,而getty程序就會通過pts/*、ptmx和telnet程序往網絡上返回“login:”字符串信息。這樣,登錄程序與telnet程序就通過“僞終端”進行通信。
- telnet<--->/dev/ptmx(master)<--->pts/*(slave)<--->getty
如果一個程序把 pts/*看作是一個串行端口設備,則它對該端口的讀/寫操作會反映在該邏輯終端設備對的另一個/dev/ptmx上,而/dev/ptmx則是另一個程序用於讀寫操作的邏輯設備。這樣,兩個程序就可以通過這種邏輯設備進行互相交流,這很象是邏輯設備對之間的管道操作。對於pts/*,任何設計成使用一個串行端口設備的程序都可以使用該邏輯設備。但對於使用/dev/ptmx的程序,則需要專門設計來使用/dev/ptmx邏輯設備。
通過使用適當的軟件,就可以把兩個甚至多個僞終端設備連接到同一個物理串行端口上。
-
- 實驗:
- 1、在X下打開一個或N個終端窗口
- 2、#ls /dev/pts/*
- 3、關閉這個X下的終端窗口,再次運行;比較兩次輸出信息就明白了。
- 輸出爲/dev/ptmx /dev/pts/1存在一(master)對多(slave)的情況
- 3、 串口終端(/dev/ttySn)
串行端口終端(Serial Port Terminal)是使用計算機串行端口連接的終端設備。計算機把每個串行端口都看作是一個字符設備。有段時間串行端口設備通常被稱爲終端設備,那時它的最大用途就是用來連接終端,所以這些串行端口所對應的設備名稱是/dev/tts/0(或/dev/ttyS0)、/dev/tts/1(或/dev /ttyS1)等,設備號分別是(4,0)、(4,1)等(對應於win系統下的COM1、COM2等)。若要向一個端口發送數據,可以在命令行上把標準輸出重定向到這些特殊文件名上即可。
例如,在命令行提示符下鍵入:echo tekkaman> /dev/ttyS1會把“tekkaman”發送到連接在ttyS1(COM2)端口的設備上。
在2.6以後的內核中,部分三星芯片(例如S3C24x0等)將串口終端設備節點命名爲ttySACn。TI的Omap系列芯片從2.6.37開始芯片自帶的UART設備開始使用專有的的omap-uart驅動,故設備節點命名爲ttyOn,以區別於使用8250驅動時的設備名“ttySn”。
- 4、 其它類型終端
還針對很多不同的字符設備存在有很多其它種類的終端設備特殊文件,例如針對ISDN設備的/dev/ttyIn終端設備等。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
其實在理解以上概念的時候,如果瞭解終端的發展歷程,就可以比較容易理解tty、終端的概念。所以請大家閱讀最後推薦的wiki英文網頁,有助於理解上面的概念。當然,內核文檔也是必不可少的參考資料,我順手翻譯了一下。
內核文檔/Documentation/devices.txt翻譯節選:
- **** 終端設備
- Terminal, or TTY devices are a special class of character devices. A
- terminal device is any device that could act as a controlling terminal
- for a session; this includes virtual consoles, serial ports, and
- pseudoterminals .
- 終端或這TTY設備是一類特殊的字符設備。
- 一個終端設備是任何對於一個會話可以作爲控制終端的設備。
- 這包括虛擬控制檯、串口和僞終端(PTYs)。
- All terminal devices share a common set of capabilities known as line
- disciplines; these include the common terminal line discipline as well
- as SLIP and PPP modes.
- 所有終端設備共享一系列常規能力-線路規程。
- 這包含常見的終端線路規程,例如SLIP和PPP模式。
- All terminal devices are named similarly; this section explains the
- naming and use of the various types of TTYs. Note that the naming
- conventions include several historical warts; some of these are
- Linux-specific, some were inherited from other systems, and some
- reflect Linux outgrowing a borrowed convention.
- 所有終端設備的命名都比較簡單。本節介紹不同類型TTY的命名和用途。
- 注意命名的約定包含了一些歷史需求:
- 某些是Linux特定的,
- 某些是從其他的系統中繼承下來的,
- 還有一些則反映了Linux從借鑑來的約定中發展而來的。
- A hash mark (#) in a device name is used here to indicate a decimal
- number without leading zeroes.
- 設備名中的(#)標誌用於標識一個不以0開頭的10進制數。
- Virtual consoles and the console device
- 虛擬控制檯和控制檯設備
- Virtual consoles are full-screen terminal displays on the system video
- monitor. Virtual consoles are named /dev/tty#, with numbering
- starting at /dev/tty1; /dev/tty0 is the current virtual console.
- /dev/tty0 is the device that should be used to access the system video
- card on those architectures for which the frame buffer devices
- (/dev/fb*) are not applicable. Do not use /dev/console
- for this purpose.
- 虛擬控制檯是在系統視頻監視器上全屏的顯示終端。
- 虛擬控制檯設備名爲/dev/tty#,編號開始於/dev/tty1。
- /dev/tty0是當前虛擬控制檯。
- /dev/tty0在那些幀緩衝設備(/dev/fb*)不適用的構架下可以被用來訪問系統顯卡。
- 而/dev/console並不用於此目的。
- The console device, /dev/console, is the device to which system
- messages should be sent, and on which logins should be permitted in
- single-user mode. Starting with Linux 2.1.71, /dev/console is managed
- by the kernel; for previous versions it should be a symbolic link to
- either /dev/tty0, a specific virtual console such as /dev/tty1, or to
- a serial port primary (tty*, not cu*) device, depending on the
- configuration of the system.
- 控制檯設備/dev/console是一個接受系統信息並在單用戶模式下允許登錄的設備。
- 從Linux 2.1.71開始,/dev/console由內核管理,
- 而以前的版本是一個到/dev/tty0、一個特定的虛擬控制檯(如/dev/tty1)或者一個串口主(tty*,非cu*)設備動態鏈接,這些依賴系統配置。
- Serial ports
- 串行端口
- Serial ports are RS-232 serial ports and any device which simulates
- one, either in hardware (such as internal modems) or in software (such
- as the ISDN driver.) Under Linux, each serial ports has two device
- names, the primary or callin device and the alternate or callout one.
- Each kind of device is indicated by a different letter. For any
- letter X, the names of the devices are /dev/ttyX# and /dev/cux#,
- respectively; for historical reasons, /dev/ttyS# and /dev/ttyC#
- correspond to /dev/cua# and /dev/cub#. In the future, it should be
- expected that multiple letters will be used; all letters will be upper
- case for the "tty" device (e.g. /dev/ttyDP#) and lower case for the
- "cu" device (e.g. /dev/cudp#).
- 串行端口是RS-232串口和任何類似的設備,無論是硬件的(如內部調制解調器)或者軟件(如ISDN驅動)。
- 在Linux下,每個串口有兩個設備名,主要的(callin設備)和備用的(callout設備),每類設備都通過不同的字母標識。對於任何字母X,設備名分別是/dev/ttyX# 和/dev/cux#;由於歷史原因,/dev/ttyS#和/dev/ttyC#對應於/dev/cua#和/dev/cub#。未來,對於“tty”多字母的名字將會被使用,所有的字母都將是大寫(如/dev/ttyDP#),對於"cu"設備則使用小寫字母(如/dev/cudp#)。
- The names /dev/ttyQ# and /dev/cuq# are reserved for local use.
- 名字(/dev/ttyQ#和/dev/cuq#)保留,用於本地使用。
- The alternate devices provide for kernel-based exclusion and somewhat
- different defaults than the primary devices. Their main purpose is to
- allow the use of serial ports with programs with no inherent or broken
- support for serial ports. Their use is deprecated, and they may be
- removed from a future version of Linux.
- 備用設備提供基於內核的exclusion和某些與主要設備不同的默認配置。他們的主要目的是允許那些對於串口並非內部支持或是有一定問題的程序使用串口。他們的使用已經過時,他們可能會從未來的Linux版本中刪除。
- Arbitration of serial ports is provided by the use of lock files with
- the names /var/lock/LCK..ttyX#. The contents of the lock file should
- be the PID of the locking process as an ASCII number.
- 串口的仲裁是通過鎖文件(/var/lock/LCK..ttyX#)來提供的。
- 鎖文件的內容應該是鎖定進程PID的ASCII碼。
- It is common practice to install links such as /dev/modem
- which point to serial ports. In order to ensure proper locking in the
- presence of these links, it is recommended that software chase
- symlinks and lock all possible names; additionally, it is recommended
- that a lock file be installed with the corresponding alternate
- device. In order to avoid deadlocks, it is recommended that the locks
- are acquired in the following order, and released in the reverse:
- 安裝一個例如/dev/modem的鏈接來指向串口是常見的做法。
- 爲了確保適當鎖定在這些環節的存在,建議軟件追蹤符號並鎖定所有可能的名字;
- 此外,建議爲相應的備用設備安裝一個鎖文件。
- 爲了避免死鎖,建議按以下順序獲取鎖,並按反向的順序釋放:
- 1. The symbolic link name, if any (/var/lock/LCK..modem)
- 2. The "tty" name (/var/lock/LCK..ttyS2)
- 3. The alternate device name (/var/lock/LCK..cua2)
- 1、符號鏈接名,如果有(/var/lock/LCK..modem)
- 2、“tty”名(/var/lock/LCK..ttyS2)
- 3、備用設備名(/var/lock/LCK..cua2)
- In the case of nested symbolic links, the lock files should be
- installed in the order the symlinks are resolved.
- 在符號鏈接嵌套的情況下,鎖定文件應按照符號鏈接的順序來安裝以解決問題。
- Under no circumstances should an application hold a lock while waiting
- for another to be released. In addition, applications which attempt
- to create lock files for the corresponding alternate device names
- should take into account the possibility of being used on a non-serial
- port TTY, for which no alternate device would exist.
- 在任何情況下,應用程序應該等待另一個程序釋放鎖後,持有這個鎖。
- 此外,試圖爲相應的備用設備名創建鎖文件的應用程序應考慮被用於非串口的TTY端口的可能性,此時沒有備用設備存在。
- Pseudoterminals (PTYs)
- 僞終端(PTYs)
- Pseudoterminals, or PTYs, are used to create login sessions or provide
- other capabilities requiring a TTY line discipline (including SLIP or
- PPP capability) to arbitrary data-generation processes. Each PTY has
- a master side, named /dev/pty[p-za-e][0-9a-f], and a slave side, named
- /dev/tty[p-za-e][0-9a-f]. The kernel arbitrates the use of PTYs by
- allowing each master side to be opened only once.
- 僞終端(或PTYs)用於創建登錄會話或提供給其他需要tty線路規程(包括SLIP或PPP能力)能力以生成數據的進程。
- 每個PTY有一個主端(/dev/pty[p-za-e][0-9a-f])和一個從端(/dev/tty[p-za-e][0-9a-f])。
- 內核通過只允許每個主端僅允許打開一次來仲裁PTY的使用。
- Once the master side has been opened, the corresponding slave device
- can be used in the same manner as any TTY device. The master and
- slave devices are connected by the kernel, generating the equivalent
- of a bidirectional pipe with TTY capabilities.
- 一旦主端被打開,相應的從設備可以像任何TTY設備一樣的方式被使用。
- 主從設備都和內核連接,產生相當於一個帶TTY功能的雙向管道。
- Recent versions of the Linux kernels and GNU libc contain support for
- the System V/Unix98 naming scheme for PTYs, which assigns a common
- device, /dev/ptmx, to all the masters (opening it will automatically
- give you a previously unassigned PTY) and a subdirectory, /dev/pts,
- for the slaves; the slaves are named with decimal integers (/dev/pts/#
- in our notation). This removes the problem of exhausting the
- namespace and enables the kernel to automatically create the device
- nodes for the slaves on demand using the "devpts" filesystem.
- Linux內核的最近版本和GNU庫包含了對於System V和Unix98對PTY命名方式的支持。
- 它分配一個共用的設備(/dev/ptmx)給所有的主端(打開它會自動給你一個以前未分配的PTY)和一個子目錄(/dev/pts)用於從端;從端通過十進制整數(/dev/pts/#)命名。
- 這消除了命名空間枯竭的問題,並使內核通過“devpts”文件系統按需自動爲從端動創建設備節點。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
推薦閱讀:《Linux C編程一站式學習》----第 34 章 終端、作業控制與守護進程---1. 終端
wiki百科關於終端的網頁:Computer terminal | System console | Linux console
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
以上是我參考了網上的資料後對tty的認識整理,參考資料如下:
終端tty、虛擬控制檯、FrameBuffer的切換過程詳解