經過《Linux 終端(TTY)》一文咱們瞭解到:咱們常說的終端分爲終端 tty1-6 和僞終端。使用 tty1-6 的狀況通常爲 Linux 系統直接連了鍵盤和顯示器,或者是使用了 vSphere console 等虛擬化方案,其它狀況下使用的都是僞終端。本文將介紹僞終端的基本概念。本文中演示部分使用的環境爲 ubuntu 18.04。html
僞終端(pseudo terminal,有時也被稱爲 pty)是指僞終端 master 和僞終端 slave 這一對字符設備。其中的 slave 對應 /dev/pts/ 目錄下的一個文件,而 master 則在內存中標識爲一個文件描述符(fd)。僞終端由終端模擬器提供,終端模擬器是一個運行在用戶態的應用程序。linux
Master 端是更接近用戶顯示器、鍵盤的一端,slave 端是在虛擬終端上運行的 CLI(Command Line Interface,命令行接口)程序。Linux 的僞終端驅動程序,會把 master 端(如鍵盤)寫入的數據轉發給 slave 端供程序輸入,把程序寫入 slave 端的數據轉發給 master 端供(顯示器驅動等)讀取。請參考下面的示意圖(此圖來自互聯網):shell
咱們打開的終端桌面程序,好比 GNOME Terminal,實際上是一種終端模擬軟件。當終端模擬軟件運行時,它經過打開 /dev/ptmx 文件建立了一個僞終端的 master 和 slave 對,並讓 shell 運行在 slave 端。當用戶在終端模擬軟件中按下鍵盤按鍵時,它產生字節流並寫入 master 中,shell 進程即可從 slave 中讀取輸入;shell 和它的子程序,將輸出內容寫入 slave 中,由終端模擬軟件負責將字符打印到窗口中。ubuntu
僞終端大概有三類使用場景:segmentfault
Linux 中爲何要提出僞終端這個概念呢?shell 等命令行程序不能夠直接從顯示器和鍵盤讀取數據嗎?
爲了同屏運行多個終端模擬器、並實現遠程登陸,還真不能讓 shell 直接跨過僞終端這一層。在操做系統的一大思想——虛擬化的指導下,爲多個終端模擬器、遠程用戶分配多個虛擬的終端是有必要的。上圖中的 shell 使用的 slave 端就是一個虛擬化的終端。Master 端是模擬用戶一端的交互。之因此稱爲虛擬化的終端,是由於它除了轉發數據流外,還要有點終端的樣子。服務器
僞終端本質上是運行在用戶態的終端模擬器建立的一對字符設備。其中的 slave 對應 /dev/pts/ 目錄下的一個文件,而 master 則在內存中標識爲一個文件描述符(fd)。對於僞終端來講,重點是軟件仿真終端程序運行在用戶空間,這是它與終端的本質區別,請參考下面的示意圖:ssh
/dev/ptmx 是一個字符設備文件,當進程打開 /dev/ptmx 文件時,進程會同時得到一個指向 pseudoterminal master(ptm)的文件描述符和一個在 /dev/pts 目錄中建立的 pseudoterminal slave(pts) 設備。經過打開 /dev/ptmx 文件得到的每一個文件描述符都是一個獨立的 ptm,它有本身關聯的 pts,ptmx(能夠認爲內存中有一個 ptmx 對象)在內部會維護該文件描述符和 pts 的對應關係,對這個文件描述符的讀寫都會被 ptmx 轉發到對應的 pts。咱們能夠經過 lsof 命令查看 ptmx 打開的文件描述符:spa
$ sudo lsof /dev/ptmx
通常狀況下咱們經過遠程鏈接的方式執行命令時,進程的標準輸入、標準輸出和標準錯誤輸出都會綁定到僞終端上,下面是一個簡單的 demo 程序:操作系統
#include <stdio.h> #include <unistd.h> int main() { printf("PID : %d\n", getpid()); sleep(200); printf("\n"); return 0; }
把這段代碼保存在文件 mydemo.c 中,而後執行下面的命令編譯並執行該程序:.net
$ gcc -Wall mydemo.c -o demo $ ./demo
demo 程序輸出了本身進程的 PID,如今另外開一個終端執行 lsof 命令:
$ lsof -p 17981
能夠看到進程的 0u(標準輸入)、1u(標準輸出)、2u(標準錯誤輸出)都綁定到了僞終端 /dev/pts/0 上。
參考:
Linux TTY/PTS概述
The TTY demystified
僞終端 pts man page
僞終端 pty man page