成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

當你在終端上按下一個鍵時會發生什么?

系統 Linux
在上個星期,我使用 xterm.js 在瀏覽器中顯示了一個交互式終端,我終于想到要問一個相當基本的問題:當你在終端中按下鍵盤上的一個鍵(比如 Delete,或 Escape,或 a),發送了哪些字節?

我對終端Terminal是怎么回事困惑了很久。

但在上個星期,我使用 ??xterm.js??? 在瀏覽器中顯示了一個交互式終端,我終于想到要問一個相當基本的問題:當你在終端中按下鍵盤上的一個鍵(比如 ??Delete???,或 ??Escape???,或 ??a??),發送了哪些字節?

像往常一樣,我們將通過做一些實驗來回答這個問題,看看會發生什么 : )

遠程終端是非常古老的技術

首先,我想說的是,用 ??xterm.js?? 在瀏覽器中顯示一個終端可能看起來像一個新事物,但它真的不是。在 70 年代,計算機很昂貴。因此,一個機構的許多員工會共用一臺電腦,每個人都可以有自己的 “終端” 來連接該電腦。

例如,這里有一張 70 年代或 80 年代的 VT100 終端的照片。這看起來像是一臺計算機(它有點大!),但它不是 —— 它只是顯示實際計算機發送的任何信息。

DEC VT100終端

DEC VT100終端

當然,在 70 年代,他們并沒有使用 Websocket 來做這個,但來回發送的信息的方式和當時差不多。

(照片中的終端是來自西雅圖的 ??活電腦博物館???Living Computer Museum,我曾經去過那里,并在一個非常老的 Unix 系統上用 ??ed?? 編寫了 FizzBuzz,所以我有可能真的用過那臺機器或它的一個兄弟姐妹!我真的希望活電腦博物館能再次開放,能玩到老式電腦是非常酷的。)

發送了什么信息?

很明顯,如果你想連接到一個遠程計算機(用 ??ssh??? 或使用 ??xterm.js?? 和 Websocket,或其他任何方式),那么需要在客戶端和服務器之間發送一些信息。

具體來說:

客戶端 需要發送用戶輸入的鍵盤信息(如 ??ls -l??)。 服務器 需要告訴客戶端在屏幕上顯示什么。

讓我們看看一個真正的程序,它在瀏覽器中運行一個遠程終端,看看有哪些信息會被來回發送!

我們將使用 goterm 來進行實驗

我在 GitHub 上發現了這個叫做 ??goterm??? 的小程序,它運行一個 Go 服務器,可以讓你在瀏覽器中使用 ??xterm.js?? 與終端進行交互。這個程序非常不安全,但它很簡單,很適合學習。

我 ??復刻了它???,使它能與最新的 ??xterm.js?? 一起工作,因為它最后一次更新是在 6 年前。然后,我添加了一些日志語句,以打印出每次通過 WebSocket 發送/接收的字節數。

讓我們來看看在幾個不同的終端交互過程中的發送和接收情況吧!

示例:ls

首先,讓我們運行 ??ls???。下面是我在 ??xterm.js?? 終端上看到的情況:

    ~:/play$ ls
file
~:/play$

以下是發送和接收的內容:(在我的代碼中,我記錄了每次客戶端發送的字節:??sent: [bytes]???,每次它從服務器接收的字節:??recv: [bytes]??)

    sent: "l"
recv: "l"
sent: "s"
recv: "s"
sent: "\r"
recv: "\r\n\x1b[?2004l\r"
recv: "file\r\n"
recv: "\x1b[~:/play$ "

我在這個輸出中注意到 3 件事:

  1. 回顯:客戶端發送??l???,然后立即收到一個??l??? 發送回來。我想這里的意思是,客戶端真的很笨 —— 它不知道當我輸入??l??? 時,我想讓??l?? 被回顯到屏幕上。它必須由服務器進程明確地告訴它來顯示它。
  2. 換行:當我按下回車鍵時,它發送了一個??\r'(回車)符號,而不是??\n'(換行)。
  3. 轉義序列:??\x1b??? 是 ASCII 轉義字符,所以??\x1b[?2004h?? 是告訴終端顯示什么或其他東西。我想這是一個顏色序列,但我不確定。我們稍后會詳細討論轉義序列。

好了,現在我們來做一些稍微復雜的事情。

示例:Ctrl+C

接下來,讓我們看看當我們用 ??Ctrl+C?? 中斷一個進程時會發生什么。下面是我在終端中看到的情況:

    ~:/play$ cat
^C
~:/play$

而這里是客戶端發送和接收的內容。

    sent: "c"
recv: "c"
sent: "a"
recv: "a"
sent: "t"
recv: "t"
sent: "\r"
recv: "\r\n\x1b[?2004l\r"
sent: "\x03"
recv: "^C"
recv: "\r\n"
recv: "\x1b[?2004h"
recv: "~:/play$ "

當我按下 ??Ctrl+C??? 時,客戶端發送了 ??\x03???。如果我查 ASCII 表,??\x03??? 是 “文本結束”,這似乎很合理。我認為這真的很酷,因為我一直對 ??Ctrl+C??? 的工作原理有點困惑 —— 很高興知道它只是在發送一個 ??\x03?? 字符。

我相信當我們按 ??Ctrl+C??? 時,??cat??? 被中斷的原因是服務器端的 Linux 內核收到這個 ??\x03??? 字符,識別出它意味著 “中斷”,然后發送一個 ??SIGINT?? 到擁有偽終端的進程組。所以它是在內核而不是在用戶空間處理的。

示例:Ctrl+D

讓我們試試完全相同的事情,只是用 ??Ctrl+D??。下面是我在終端看到的情況:

    ~:/play$ cat
~:/play$

而這里是發送和接收的內容:

    sent: "c"
recv: "c"
sent: "a"
recv: "a"
sent: "t"
recv: "t"
sent: "\r"
recv: "\r\n\x1b[?2004l\r"
sent: "\x04"
recv: "\x1b[?2004h"
recv: "~:/play$ "

它與 ??Ctrl+C??? 非常相似,只是發送 ??\x04??? 而不是 ??\x03???。很好!??\x04?? 對應于 ASCII “傳輸結束”。

Ctrl + 其它字母呢?

接下來我開始好奇 —— 如果我發送 ??Ctrl+e??,會發送什么字節?

事實證明,這只是該字母在字母表中的編號,像這樣。

  • ??Ctrl+a?? => 1
  • ??Ctrl+b?? => 2
  • ??Ctrl+c?? => 3
  • ??Ctrl+d?? => 4
  • ...
  • ??Ctrl+z?? => 26

另外,??Ctrl+Shift+b??? 的作用與 ??Ctrl+b??? 完全相同(它寫的是??0x2??)。

鍵盤上的其他鍵呢?下面是它們的映射情況:

  • ??Tab??? -> 0x9(與??Ctrl+I?? 相同,因為 I 是第 9 個字母)
  • ??Escape??? ->??\x1b??
  • ??Backspace??? ->??\x7f??
  • ??Home??? ->??\x1b[H??
  • ??End??? ->??\x1b[F??
  • ??Print Screen??? ->??\x1b\x5b\x31\x3b\x35\x41??
  • ??Insert??? ->??\x1b\x5b\x32\x7e??
  • ??Delete??? ->??\x1b\x5b\x33\x7e??
  • 我的??Meta?? 鍵完全沒有作用

那 ??Alt??? 呢?根據我的實驗(和一些搜索),似乎 ??Alt??? 和 ??Escape??? 在字面上是一樣的,只是按 ??Alt??? 本身不會向終端發送任何字符,而按 ??Escape?? 本身會。所以:

  • ??alt + d??? =>??\x1bd??(其他每個字母都一樣)
  • ??alt + shift + d??? =>??\x1bD??(其他每個字母都一樣)
  • 諸如此類

讓我們再看一個例子!

示例:nano

下面是我運行文本編輯器 ??nano?? 時發送和接收的內容:

    recv: "\r\x1b[~:/play$ "
sent: "n" [[]byte{0x6e}]
recv: "n"
sent: "a" [[]byte{0x61}]
recv: "a"
sent: "n" [[]byte{0x6e}]
recv: "n"
sent: "o" [[]byte{0x6f}]
recv: "o"
sent: "\r" [[]byte{0xd}]
recv: "\r\n\x1b[?2004l\r"
recv: "\x1b[?2004h"
recv: "\x1b[?1049h\x1b[22;0;0t\x1b[1;16r\x1b(B\x1b[m\x1b[4l\x1b[?7h\x1b[39;49m\x1b[?1h\x1b=\x1b[?1h\x1b=\x1b[?25l"
recv: "\x1b[39;49m\x1b(B\x1b[m\x1b[H\x1b[2J"
recv: "\x1b(B\x1b[0;7m GNU nano 6.2 \x1b[44bNew Buffer \x1b[53b \x1b[1;123H\x1b(B\x1b[m\x1b[14;38H\x1b(B\x1b[0;7m[ Welcome to nano. For basic help, type Ctrl+G. ]\x1b(B\x1b[m\r\x1b[15d\x1b(B\x1b[0;7m^G\x1b(B\x1b[m Help\x1b[15;16H\x1b(B\x1b[0;7m^O\x1b(B\x1b[m Write Out \x1b(B\x1b[0;7m^W\x1b(B\x1b[m Where Is \x1b(B\x1b[0;7m^K\x1b(B\x1b[m Cut\x1b[15;61H"

你可以看到一些來自用戶界面的文字,如 “GNU nano 6.2”,而這些 ??\x1b[27m?? 的東西是轉義序列。讓我們來談談轉義序列吧!

ANSI 轉義序列

上面這些 ??nano??? 發給客戶端的 ??\x1b[??? 東西被稱為“轉義序列”或 “轉義代碼”。這是因為它們都是以 “轉義”字符 ??\x1b??? 開頭。它們可以改變光標的位置,使文本變成粗體或下劃線,改變顏色,等等。??維基百科介紹了一些歷史??,如果你有興趣的話可以去看看。

舉個簡單的例子:如果你在終端運行

    echo -e '\e[0;31mhi\e[0m there'

它將打印出 “hi there”,其中 “hi” 是紅色的,“there” 是黑色的。??本頁?? 有一些關于顏色和格式化的轉義代碼的例子。

我認為有幾個不同的轉義代碼標準,但我的理解是,人們在 Unix 上使用的最常見的轉義代碼集來自 VT100(博客文章頂部圖片中的那個老終端),在過去的 40 年里沒有真正改變。

轉義代碼是為什么你的終端會被搞亂的原因,如果你 ??cat??? 一些二進制數據到你的屏幕上 —— 通常你會不小心打印出一堆隨機的轉義代碼,這將搞亂你的終端 —— 如果你 ??cat??? 足夠多的二進制數據到你的終端,那里一定會有一個 ??0x1b?? 的字節。

可以手動輸入轉義序列嗎?

在前面幾節中,我們談到了 ??Home??? 鍵是如何映射到 ??\x1b[H??? 的。這 3 個字節是 ??Escape + [ + H???(因為 ??Escape??? 是??\x1b??)。

如果我在 ??xterm.js??? 終端手動鍵入 ??Escape??? ,然后是 ??[???,然后是 ??H???,我就會出現在行的開頭,與我按下 ??Home?? 完全一樣。

我注意到這在我的電腦上的 Fish shell 中不起作用 —— 如果我鍵入 ??Escape???,然后輸入 ??[???,它只是打印出 ??[???,而不是讓我繼續轉義序列。我問了我的朋友 Jesse,他寫過 ??一堆 Rust 終端代碼??,Jesse 告訴我,很多程序為轉義代碼實現了一個 超時 —— 如果你在某個最小的時間內沒有按下另一個鍵,它就會決定它實際上不再是一個轉義代碼了。

顯然,這在 Fish shell 中可以用 ??fish_escape_delay_ms??? 來配置,所以我運行了 ??set fish_escape_delay_ms 1000??,然后我就能用手輸入轉義代碼了。工作的很好!

終端編碼有點奇怪

我想在這里暫停一下,我覺得你按下的鍵被映射到字節的方式是非常奇怪的。比如,如果我們今天從頭開始設計按鍵的編碼方式,我們可能不會把它設置成這樣:

  • ??Ctrl + a??? 和??Ctrl + Shift + a?? 做的事情完全一樣。
  • ??Alt??? 與??Escape?? 是一樣的
  • 控制序列(如顏色/移動光標)使用與??Escape??? 鍵相同的字節,因此你需要依靠時間來確定它是一個控制序列還是用戶只是想按??Escape??。

但所有這些都是在 70 年代或 80 年代或什么時候設計的,然后需要永遠保持不變,以便向后兼容,所以這就是我們得到的東西 :smiley:

改變窗口大小

在終端中,并不是所有你能做的事情都是通過來回發送字節發生的。例如,當終端被調整大小時,我們必須以不同的方式告訴 Linux 窗口大小已經改變。

下面是 ??goterm?? 中用來做這件事的 Go 代碼的樣子:

    syscall.Syscall(
syscall.SYS_IOCTL,
tty.Fd(),
syscall.TIOCSWINSZ,
uintptr(unsafe.Pointer(&resizeMessage)),
)

這是在使用 ??ioctl??? 系統調用。我對 ??ioctl?? 的理解是,它是一個系統調用,用于處理其他系統調用沒有涉及到的一些隨機的東西,通常與 IO 有關,我猜。

??syscall.TIOCSWINSZ??? 是一個整數常數,它告訴 ??ioctl?? 我們希望它在本例中做哪件事(改變終端的窗口大小)。

這也是 xterm 的工作方式。

在這篇文章中,我們一直在討論遠程終端,即客戶端和服務器在不同的計算機上。但實際上,如果你使用像 xterm 這樣的終端模擬器,所有這些工作方式都是完全一樣的,只是很難注意到,因為這些字節并不是通過網絡連接發送的。

文章到此結束啦

關于終端,肯定還有很多東西要了解(我們可以討論更多關于顏色,或者原始與熟化模式,或者 Unicode 支持,或者 Linux 偽終端界面),但我將在這里停止,因為現在是晚上 10 點,這篇文章有點長,而且我認為我的大腦今天無法處理更多關于終端的新信息。

責任編輯:龐桂玉 來源: Linux中國
相關推薦

2018-01-19 12:56:19

Linux進程

2023-12-13 17:04:51

終端命令shell

2015-09-25 10:41:48

r語言

2019-09-03 14:15:05

2019-02-27 10:18:26

重置Windows 10Windows

2015-10-29 09:35:12

BAT趨勢數據

2024-01-17 11:07:09

單模光纖OS2 光纖數據中心

2024-04-02 11:31:33

USBAndroid

2019-03-19 19:19:19

Facebook微信轉型

2014-06-17 10:57:09

2016-04-08 15:13:29

人工智能阿里小Ai

2013-03-15 09:57:00

虛擬化 數據中心

2015-07-28 11:22:30

大數據浪潮

2011-03-17 15:01:11

Oracle

2013-01-17 10:09:50

JavaSpring

2021-08-11 18:23:08

數據平臺IT

2015-08-03 14:06:44

2022-02-13 15:49:15

WebAssemblKubernetes容器

2009-03-28 09:22:12

MID移動OS

2015-10-19 17:50:43

云計算IT行業DevOps
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 看亚洲a级一级毛片 | 亚洲 中文 欧美 日韩 在线观看 | 日干夜干 | 91xx在线观看| 91精品国产综合久久久久久蜜臀 | 一区视频在线播放 | 91最新视频| 99视频免费 | 中文字幕日韩欧美一区二区三区 | 天堂免费| 欧美日韩成人 | 成人妇女免费播放久久久 | 成人精品鲁一区一区二区 | 在线成人av | 国产精品久久久久久久白浊 | 欧美日韩国产一区二区 | 欧美99 | 日本一级淫片免费啪啪3 | 国产日韩久久 | 中文字幕一区二区三区日韩精品 | 久久99国产精一区二区三区 | 中文成人在线 | 亚洲美女在线一区 | 国产传媒视频在线观看 | 亚洲高清在线免费观看 | 欧美一级片在线观看 | 久久精品网 | 亚洲免费av一区 | 免费三级黄 | 欧美精品久久久久 | v亚洲| 在线一区二区三区 | 亚洲高清视频一区二区 | 日韩精品成人一区二区三区视频 | 特a毛片 | 国产精品一卡二卡三卡 | 91免费在线视频 | 给我免费的视频在线观看 | 黄色电影在线免费观看 | 欧美一区二区黄 | 91久久久www播放日本观看 |