每個偽終端 (PTY) 組件(軟體、主端、從端)的職責是什麼?
我試圖弄清楚tty 是如何工作的1(每個元素的工作流程和職責)。我已經閱讀了幾篇關於它的有趣文章,但仍有一些模糊的地方。
這是我目前所理解的:
- 模擬終端
/dev/ptmx
對偽終端的主要部分進行不同的系統呼叫。- 偽終端的主機部分在 中分配一個文件
/dev/pts/[0-N]
,對應於過時的串列埠,並將一個從偽終端“附加”到它。- 從偽終端保存會話ID、前台作業、螢幕大小等資訊。
以下是我的問題:
- 除了分配從屬部分之外,ptmx 還有其他用途嗎?它是否提供某種“智能”,或者模擬終端(例如 xterm)具有像終端一樣行為的所有智能?
- 為什麼 xterm必須與 master 部分互動,因為它只轉發 slave 部分的 stdout 和 stdin?為什麼不能 直接讀寫pts文件?
- 會話 ID 是否始終附加到一個 pts 文件,反之亦然?我可以輸入一個 ps 命令並為同一個 /dev/pts/X 找到 2 個 sessionId嗎?
pts
商店還有哪些其他資訊?Xterm 是自己更新所有欄位,還是在ptm
上面添加一些“智能”?
- 我的理解基於Linus Akesson 揭秘的 TTY和Andries Brouwer 的 Linux Kernel文章,以及這些網站上的其他幾個問題
終端仿真器
主端取代了連接到終端的線路(一對 TX/RX 線)。
終端顯示它在其中一根線上接收到的字元(其中一些是控製字元,使其執行移動游標、更改顏色等操作)並在另一根線上發送與您鍵入的鍵相對應的字元。
像 xterm 這樣的終端仿真器並沒有什麼不同,只是它們不是線上路上發送和接收字元,而是在其文件描述符上讀取和寫入字元到主端。一旦他們產生了從終端,並在上面啟動了你的 shell,他們就不再碰它了。除了模擬這對線之外,xterm 還可以通過該文件描述符將某些線路規程屬性更改到主端。例如,他們可以更新大小屬性,以便將 SIGWINCH 發送到與從屬 pty 互動的應用程序,以通知它們更改的大小。
除此之外,終端/終端仿真器幾乎沒有智能。
您寫入終端設備(如 pty 從站)的內容是您要在此處顯示的內容,從中讀取的內容是您在此處輸入的內容,因此終端仿真器讀取或寫入該設備沒有意義. 他們是另一端的人。
tty 線紀律
很多情報都在tty線紀律中。線路規程是一個軟體模組(位於驅動程序中,在核心中),位於該設備和線路/線路(pty 的主端)之間的串列/pty 設備之上。
串列線的另一端可以有一個終端,也可以是滑鼠或另一台用於聯網的電腦。例如,您可以附加一個 SLIP 線路規程以在串列設備(或 pty 設備)之上獲取網路介面,或者您可以擁有一個tty線路規程。tty 線路規程是至少在 Linux 上用於串列和 pty 設備的預設線路規程。在 Linux 上,您可以使用
ldattach
.您可以通過發出命令來查看禁用 tty 行規則的效果
stty raw -echo
(注意 bash 提示符或其他互動式應用程序,例如vi
將終端設置為所需的確切模式,因此您想使用類似的啞應用程序cat
來體驗)。然後,寫入從終端設備的所有內容都會立即發送到主設備以供 xterm 讀取,並且 xterm 寫入主設備的每個字元都可以立即可供從設備讀取。線路規程是實現終端設備內部線路編輯器的地方。例如
stty icanon echo
(預設情況下),當您鍵入 時a
,xterm 會寫入a
主伺服器,然後行規則將其回顯(使 aa
可用於xterm
顯示以供閱讀),但不會使任何內容可用於從機端讀取. 然後,如果您鍵入退格鍵,xterm 發送一個^?
or^H
字元,行規則(如^?
or^H
對應於行規則設置)發送erase
回 master a^H
,space
並^H
刪除xterm``a
您剛剛在它的螢幕上輸入了內容,但仍然沒有向從從端讀取的應用程序發送任何內容,它只是更新其內部行編輯器緩衝區以刪除a
您之前輸入的內容。然後,當您按 Enter 鍵時,xterm 發送
^M
(CR),該行規則將輸入轉換為 ^J (LF),並將您目前輸入的內容髮送到從屬端讀取(正在讀取的應用程序/dev/pts/x
將接收你已經輸入了包括 LF,但不是a
因為你已經刪除了它),而在主端,它發送一個 CR 和 LF 將游標移動到下一行和螢幕的開頭。線路紀律還負責在收到主控端的字元等時向終端的前台程序組****發送信號。
SIGINT
^C
許多互動式終端應用程序禁用了該行學科的大部分*功能以自行實施。*但無論如何,請注意終端 (
xterm
) 幾乎沒有參與其中(除了顯示它被告知要顯示的內容)。每個程序和每個終端設備只能有一個會話。會話可以附加一個控制終端,但不是必須的(所有會話在沒有終端的情況下開始,直到它們打開一個終端)。
xterm
,在它派生來執行你的 shell 的過程中,通常會創建一個新會話(因此從你啟動的終端中分離(xterm
如果有的話))/dev/pts/x
,通過將該終端設備附加到新會話來打開它產生的新會話。然後它將在該程序中執行您的 shell,因此您的 shell 將成為會話負責人。您的 shell 或該會話中的任何互動式 shell 通常會處理程序組和tcsetpgrp()
, 來設置該終端的前台和後台作業。至於具有 tty 規則(串列或 pty)的終端設備儲存了哪些資訊,這通常是
stty
命令顯示和修改的內容。所有學科配置:終端螢幕大小、本地、輸入輸出標誌、特殊字元設置(如 ^C、^Z…)、輸入和輸出速度(與 ptys 無關)。這對應於 Linux上映射到/ ioctls的tcgetattr()
/函式和/用於螢幕大小。您可能會爭辯說,目前前台程序組是儲存在終端設備(/ 、ioctls)或目前輸入或輸出緩衝區中的另一個資訊。tcsetattr()``TCGETS``TCSETS``TIOCGWINSZ``TIOCSWINSZ``tcsetpgrp()``tcgetpgrp()``TIOC{G,S}PGRP
請注意,終端設備中儲存的螢幕尺寸資訊可能無法反映真實情況。終端仿真器通常會在調整其視窗大小時設置它(通過主大小上的相同 ioctl),但如果應用程序在從屬端呼叫 ioctl 或未傳輸調整大小時(以防萬一),它可能會不同步一個 ssh 連接,這意味著另一個 pty 由
sshd
ifssh
忽略SIGWINCH
例如)。一些終端也可以通過轉義序列查詢它們的大小,因此應用程序可以通過這種方式查詢它,並使用該資訊更新線路規則。有關更多詳細資訊,您可以查看Debian 上的手冊頁
termios
和手冊頁。tty_ioctl
與其他線學科一起玩:
- 用偽終端模擬滑鼠:
socat pty,link=mouse fifo:fifo sudo inputattach -msc mouse # sets the MOUSE line discipline and specifies protocol xinput list # see the new mouse there exec 3<> fifo printf '\207\12\0' >&3 # moves the cursor 10 pixels to the right
上面,pty 的主端由 socat 終止到命名管道 (
fifo
) 上。我們將該先進先出連接到寫入 0x87 0x0a 0x00 的程序(shell),這在滑鼠系統協議中表示no button pressed, delta(x,y) = (10,0)
. 在這裡,我們(外殼)不是模擬終端,而是滑鼠,我們發送的 3 個字節不會被終端設備的應用程序讀取(可能轉換)(mouse
上面是某個設備的符號socat
連結/dev/pts/x
) ,但將被解釋為滑鼠輸入事件。 2. 創建一個 SLIP 介面:# on hostA socat tcp-listen:12345,reuseaddr pty,link=interface # after connection from hostB: sudo ldattach SLIP interface ifconfig -a # see the new interface there sudo ifconfig sl0 192.168.123.1/24 # on hostB socat -v -x pty,link=interface tcp:hostA:12345 sudo ldattach SLIP interface sudo ifconfig sl0 192.168.123.2/24 ping 192.168.123.1 # see the packets on socat output
上面,串列線被模擬
socat
為 hostA 和 hostB 之間的 TCP 套接字。SLIP 線路規程將通過該虛擬線路交換的那些字節解釋為 SLIP 封裝的 IP 數據包,以便在sl0
介面上傳遞。