Apabila kita menaip surat pada papan kekunci, bagaimanakah ia dihantar ke proses yang sepadan? Kami melihat output seperti tty1 dan pts/0 melalui ps, siapa dan arahan lain Apakah fungsi dan perbezaannya?
Sejarah TTY
Sebelum komputer yang menyokong multitasking muncul
Sebelum komputer keluar, orang ramai sudah menggunakan peranti yang dipanggil teletaip untuk berkomunikasi antara satu sama lain Maklumat kelihatan seperti berikut :
+----------+ Physical Line +----------+ | teletype |<--------------------->| teletype | +----------+ +----------+
Kedua-dua teletaip disambungkan dengan satu talian mungkin juga terdapat peranti yang serupa dengan modem pada kedua-dua hujung talian (ia diabaikan di sini apabila menaip pada papan kekunci). , data yang sepadan akan dihantar ke teletaip di hujung yang lain. Saya tidak tahu banyak tentang fungsi tertentu. (Dalam fikiran saya, gambar itu ditaip di satu hujung dan dicetak di hujung yang lain)
Ini adalah barangan antik lama dan saya tidak pernah terdedah kepadanya, jadi saya hanya boleh membuat spekulasi mudah.
Selepas kemunculan komputer yang menyokong multi-tasking
Selepas komputer menyokong multi-tasking, orang ramai berfikir untuk menyambungkan teletaip ini ke komputer sebagai terminal komputer supaya mereka boleh mengendalikan komputer.
Terdapat dua sebab utama untuk menggunakan teletaip (pendapat peribadi):
Sebenarnya, sudah terdapat sejumlah besar teletaip daripada pengeluar yang berbeza, yang boleh membuat penuh penggunaan sumber sedia ada
Rangkaian berkaitan teletaip agak matang dan mudah disambungkan
Jadi sambungan dibangunkan seperti ini:
+----------+ +----------+ +-------+ Physical Line +-------+ +------+ | | | Terminal |<->| Modem |<--------------------->| Modem |<->| UART |<->| Computer | +----------+ +-------+ +-------+ +------+ | | +----------+
Terminal di sebelah kiri ialah pelbagai jenis teletaip
Modem digunakan pada kedua-dua belah talian fizikal, yang sering kita panggil " kucing". Itu kerana rangkaian telah sejak Ia perlahan-lahan menjadi lebih maju dan semua orang boleh berkongsi sambungan. (Mungkin tekaan, mungkin salah)
UART boleh difahami sebagai peranti yang menukar isyarat teletaip kepada isyarat yang boleh dikenali oleh komputer
Subsistem TTY Kernel
Untuk menyokong teletaip ini, komputer mereka bentuk subsistem yang dipanggil TTY Struktur dalaman adalah seperti berikut:
+-----------------------------------------------+ | Kernel | | +--------+ | | +--------+ +------------+ | | | +----------------+ | | UART | | Line | | TTY |<---------->| User process A | <------>| |<->| |<->| | | +----------------+ | | driver | | discipline | | driver |<---------->| User process B | | +--------+ +------------+ | | | +----------------+ | +--------+ | | | +-----------------------------------------------+
Pemacu UART menyambung. kepada peranti UART luaran
Disiplin talian terutamanya melakukan beberapa pemprosesan input dan output Ia boleh difahami bahawa ia adalah sebahagian daripada pemacu TTY
- Pemandu TTY digunakan untuk memproses pelbagai Sejenis peranti terminal
- Proses ruang pengguna berurusan dengan terminal melalui pemacu TTY
Demi kesederhanaan, ia tidak akan disebut dalam pengenalan berikut Menyenaraikan pemandu UART dan disiplin Talian secara berasingan, mereka boleh dianggap sebagai sebahagian daripada pemandu TTYPeranti TTY<.>
Untuk setiap terminal, pemandu TTY akan mencipta peranti TTY yang sepadan dengannya , jika berbilang terminal disambungkan, ia akan kelihatan seperti ini:
Apabila pemandu menerima sambungan terminal, ia akan mencipta peranti tty yang sepadan mengikut model dan parameter terminal ( Nama peranti dalam gambar di atas dipanggil ttyS0 kerana kebanyakan sambungan terminal adalah sambungan bersiri Memandangkan setiap terminal mungkin berbeza dan mempunyai arahan khas dan tabiat penggunaannya sendiri, konfigurasi setiap peranti tty mungkin berbeza. Contohnya, apabila menekan kekunci padam, sesetengah mungkin memadam aksara sebelumnya, dan sesetengah mungkin memadam aksara berikut Jika konfigurasi tidak betul, beberapa kekunci mungkin tidak berfungsi seperti yang anda mahu . , jika konfigurasi lalai tidak selaras dengan tabiat kami, beberapa konfigurasi diperibadikan perlu dilakukan.+----------------+ | TTY Driver | | | | +-------+ | +----------------+ +------------+ | | |<---------->| User process A | | Terminal A |<--------->| ttyS0 | | +----------------+ +------------+ | | |<---------->| User process B | | +-------+ | +----------------+ | | | +-------+ | +----------------+ +------------+ | | |<---------->| User process C | | Terminal B |<--------->| ttyS1 | | +----------------+ +------------+ | | |<---------->| User process D | | +-------+ | +----------------+ | | +----------------+
Kemudian, dengan perkembangan komputer yang berterusan, peranti teletaip secara beransur-ansur hilang Kami tidak lagi memerlukan peralatan terminal khas Setiap mesin mempunyai papan kekunci dan monitor sendiri, dan setiap mesin boleh digunakan oleh mesin lain operasi dilaksanakan melalui ssh, tetapi seni bina pemacu kernel TTY tidak berubah Jika kita ingin berinteraksi dengan proses dalam sistem untuk I/O, kita masih perlu menggunakan peranti TTY, jadi pelbagai perisian simulasi terminal telah muncul juga mensimulasikan beberapa terminal biasa, seperti VT100, VT220, XTerm, dsb.
Anda boleh menggunakan arahan
Cara program menangani TTY- untuk menyenaraikan semua jenis terminal yang disokong oleh sistem
Anda boleh menggunakan arahan infocmp untuk membandingkan dua terminal Perbezaan, sebagai contoh,
toe -a
- akan mengeluarkan perbezaan antara vt100 dan vt220.
infocmp vt100 vt220
Sebelum membincangkan cara peranti TTY dicipta dan dikonfigurasikan, mari kita lihat dahulu cara TTY digunakan oleh proses :
Berikut ialah gambar rajah struktur interaksi antara tty dan proses dan peranti I/O:
#先用tty命令看看当前bash关联到了哪个tty dev@debian:~$ tty /dev/pts/1 #看tty都被哪些进程打开了 dev@debian:~$ lsof /dev/pts/1 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME bash 907 dev 0u CHR 136,1 0t0 4 /dev/pts/1 bash 907 dev 1u CHR 136,1 0t0 4 /dev/pts/1 bash 907 dev 2u CHR 136,1 0t0 4 /dev/pts/1 bash 907 dev 255u CHR 136,1 0t0 4 /dev/pts/1 lsof 1118 dev 0u CHR 136,1 0t0 4 /dev/pts/1 lsof 1118 dev 1u CHR 136,1 0t0 4 /dev/pts/1 lsof 1118 dev 2u CHR 136,1 0t0 4 /dev/pts/1 #往tty里面直接写数据跟写标准输出是一样的效果 dev@dev:~$ echo aaa > /dev/pts/2 aaa
Anda boleh memahami tty sebagai paip (paip) , tulis di satu hujung Kandungan boleh dibaca dari hujung yang satu lagi dan sebaliknya.
这里input和output可以简单的理解为键盘和显示器,后面会介绍在各种情况下input/ouput都连接的什么东西。
tty里面有一个很重要的属性,叫Foreground process group,记录了当前前端的进程组是哪一个。process group的概念会在下一篇文章中介绍,这里可以简单的认为process group里面只有一个进程。
当pts/1收到input的输入后,会检查当前前端进程组是哪一个,然后将输入放到进程组的leader的输入缓存中,这样相应的leader进程就可以通过read函数得到用户的输入
当前端进程组里面的进程往tty设备上写数据时,tty就会将数据输出到output设备上
当在shell中执行不同的命令时,前端进程组在不断的变化,而这种变化会由shell负责更新到tty设备中
从上面可以看出,进程和tty打交道很简单,只要保证后台进程不要读写tty就可以了,即写后台程序时,要将stdin/stdout/stderr重定向到其它地方(当然deamon程序还需要做很多其它处理)。
先抛出两个问题(后面有答案):
当非前端进程组里面的进程(后台进程)往tty设备上写数据时,会发生什么?会输出到outpu上吗?
当非前端进程组里面的进程(后台进程)从tty设备上读数据时,会发生什么?进程会阻塞吗?
TTY是如何被创建的
下面介绍几种常见的情况下tty设备是如何创建的,以及input和output设备都是啥。
键盘显示器直连(终端)
先看图再说话:
+-----------------------------------------+ | Kernel | | +--------+ | +----------------+ +----------+ | +-------------------+ | tty1 |<---------->| User processes | | Keyboard |--------->| | +--------+ | +----------------+ +----------+ | | Terminal Emulator |<->| tty2 |<---------->| User processes | | Monitor |<---------| | +--------+ | +----------------+ +----------+ | +-------------------+ | tty3 |<---------->| User processes | | +--------+ | +----------------+ | | +-----------------------------------------+
键盘、显示器都和内核中的终端模拟器相连,由模拟器决定创建多少tty,比如你在键盘上输入ctrl+alt+F1时,模拟器首先捕获到该输入,然后激活tty1,这样键盘的输入会转发到tty1,而tty1的输出会转发到显示器,同理用输入ctrl+alt+F2,就会切换到tty2。
当模拟器激活tty时如果发现没有进程与之关联,意味着这是第一次打开该tty,于是会启动配置好的进程并和该tty绑定,一般该进程就是负责login的进程。
当切换到tty2后,tty1里面的输出会输出到哪里呢?tty1的输出还是会输出给模拟器,模拟器里会有每个tty的缓存,不过由于模拟器的缓存空间有限,所以下次切回tty1的时候,只能看到最新的输出,以前的输出已经不在了。
不确定这里的终端模拟器对应内核中具体的哪个模块,但肯定有这么个东西存在
SSH远程访问
+----------+ +------------+ | Keyboard |------>| | +----------+ | Terminal | | Monitor |<------| | +----------+ +------------+ | | ssh protocol | ↓ +------------+ | | | ssh server |--------------------------+ | | fork | +------------+ | | ↑ | | | | write | | read | | | | +-----|---|-------------------+ | | | | | ↓ | ↓ | +-------+ | +-------+ | +--------+ | pts/0 |<---------->| shell | | | | +-------+ | +-------+ | | ptmx |<->| pts/1 |<---------->| shell | | | | +-------+ | +-------+ | +--------+ | pts/2 |<---------->| shell | | +-------+ | +-------+ | Kernel | +-----------------------------+
这里的Terminal可能是任何地方的程序,比如windows上的putty,所以不讨论客户端的Terminal程序是怎么和键盘、显示器交互的。由于Terminal要和ssh服务器打交道,所以肯定要实现ssh的客户端功能。
这里将建立连接和收发数据分两条线路解释,为了描述简洁,这里以sshd代替ssh服务器程序:
建立连接
1.Terminal请求和sshd建立连接
2.如果验证通过,sshd将创建一个新的session
3.调用API(posix_openpt())请求ptmx创建一个pts,创建成功后,sshd将得到和ptmx关联的fd,并将该fd和session关联起来。
#pty(pseudo terminal device)由两部分构成,ptmx是master端,pts是slave端, #进程可以通过调用API请求ptmx创建一个pts,然后将会得到连接到ptmx的读写fd和一个新创建的pts, #ptmx在内部会维护该fd和pts的对应关系,随后往这个fd的读写会被ptmx转发到对应的pts。 #这里可以看到sshd已经打开了/dev/ptmx dev@debian:~$ sudo lsof /dev/ptmx COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sshd 1191 dev 8u CHR 5,2 0t0 6531 /dev/ptmx sshd 1191 dev 10u CHR 5,2 0t0 6531 /dev/ptmx sshd 1191 dev 11u CHR 5,2 0t0 6531 /dev/ptmx
4.同时sshd创建shell进程,将新创建的pts和shell绑定
收发消息
1.Terminal收到键盘的输入,Terminal通过ssh协议将数据发往sshd
2.sshd收到客户端的数据后,根据它自己管理的session,找到该客户端对应的关联到ptmx上的fd
3.往找到的fd上写入客户端发过来的数据
4.ptmx收到数据后,根据fd找到对应的pts(该对应关系由ptmx自动维护),将数据包转发给对应的pts
5.pts收到数据包后,检查绑定到自己上面的当前前端进程组,将数据包发给该进程组的leader
6.由于pts上只有shell,所以shell的read函数就收到了该数据包
7.shell对收到的数据包进行处理,然后输出处理结果(也可能没有输出)
8.shell通过write函数将结果写入pts
9.pts将结果转发给ptmx
10.ptmx根据pts找到对应的fd,往该fd写入结果
11.sshd收到该fd的结果后,找到对应的session,然后将结果发给对应的客户端
键盘显示器直连(图形界面)
+----------+ +------------+ | Keyboard |------>| | +----------+ | Terminal |--------------------------+ | Monitor |<------| | fork | +----------+ +------------+ | | ↑ | | | | write | | read | | | | +-----|---|-------------------+ | | | | | ↓ | ↓ | +-------+ | +-------+ | +--------+ | pts/0 |<---------->| shell | | | | +-------+ | +-------+ | | ptmx |<->| pts/1 |<---------->| shell | | | | +-------+ | +-------+ | +--------+ | pts/2 |<---------->| shell | | +-------+ | +-------+ | Kernel | +-----------------------------+
为了简化起见,本篇不讨论Linux下图形界面里Terminal程序是怎么和键盘、显示器交互的。
这里和上面的不同点就是,这里的Terminal不需要实现ssh客户端,但需要把ssh服务器要干的活也干了(当然ssh通信相关的除外)。
SSH + Screen/Tmux
常用Linux的同学应该对screen和tmux不陌生,通过它们启动的进程,就算网络断开了,也不会受到影响继续执行,下次连上去时还能看到进程的所有输出,还能继续接着干活。
这里以tmux为例介绍其原理:
+----------+ +------------+ | Keyboard |------>| | +----------+ | Terminal | | Monitor |<------| | +----------+ +------------+ | | ssh protocol | ↓ +------------+ | | | ssh server |--------------------------+ | | fork | +------------+ | | ↑ | | | | write | | read | | | | +-----|---|-------------------+ | | ↓ | | ↓ | +--------+ +-------+ | +-------+ fork +-------------+ | | ptmx |<->| pts/0 |<---------->| shell |-------->| tmux client | | +--------+ +-------+ | +-------+ +-------------+ | | | | ↑ | +--------+ +-------+ | +-------+ | | | ptmx |<->| pts/2 |<---------->| shell | | | +--------+ +-------+ | +-------+ | | ↑ | Kernel | ↑ | +-----|---|-------------------+ | | | | | | |w/r| +---------------------------+ | | | | fork | | ↓ | | +-------------+ | | | | | tmux server |<--------------------------------------------+ | | +-------------+
系统中的ptmx只有一个,上图中画出来了两个,目的是为了表明tmux服务器和sshd都用ptmx,但它们之间又互不干涉。
这种情况要稍微复杂一点,不过原理都是一样的,前半部分和普通ssh的方式是一样的,只是pts/0关联的前端进程不是shell了,而是变成了tmux客户端,所以ssh客户端发过来的数据包都会被tmux客户端收到,然后由tmux客户端转发给tmux服务器,而tmux服务器干的活和ssh的类似,也是维护一堆的session,为每个session创建一个pts,然后将tmux客户端发过来的数据转发给相应的pts。
由于tmux服务器只和tmux客户端打交道,和sshd没有关系,当终端和sshd的连接断开时,虽然pts/0会被关闭,和它相关的shell和tmux客户端也将被kill掉,但不会影响tmux服务器,当下次再用tmux客户端连上tmux服务器时,看到的还是上次的内容。
TTY和PTS的区别
从上面的流程中应该可以看出来了,对用户空间的程序来说,他们没有区别,都是一样的;从内核里面来看,pts的另一端连接的是ptmx,而tty的另一端连接的是内核的终端模拟器,ptmx和终端模拟器都只是负责维护会话和转发数据包;再看看ptmx和内核终端模拟器的另一端,ptmx的另一端连接的是用户空间的应用程序,如sshd、tmux等,而内核终端模拟器的另一端连接的是具体的硬件,如键盘和显示器。
常见的TTY配置
先先来看看当前tty的所有配置:
dev@dev:~$ stty -a speed 38400 baud; rows 51; columns 204; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0; -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel -iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc
stty还可以用来修改tty的参数,用法请参考
man stty
只要是有权限的程序,都可以通过Linux提供的API来修改TTY的配置,下面介绍一些常见的的配置项。
rows 51; columns 204;
这个配置一般由终端控制,当终端的窗口大小发生变化时,需要通过一定的手段修改该配置,比如ssh协议里面就有修改窗口大小的参数,sshd收到客户端的请求后,会通过API修改tty的这个参数,然后由tty通过信号SIGWINCH通知前端程序(比如shell或者vim),前端程序收到信号后,再去读tty的这个参数,然后就知道如何调整自己的输出排版了。
intr = ^C
tty除了在终端和前端进程之间转发数据之外,还支持很多控制命令,比如终端输入了CTRL+C,那么tty不会将该输入串转发给前端进程,而是将它转换成信号SIGINT发送给前端进程。这个就是用来配置控制命令对应的输入组合的,比如我们可以配置“intr = ^E”表示用CTRL+E代替CTRL+C。
start = ^Q; stop = ^S;
这是两个特殊的控制命令,估计经常有人会碰到,在键盘上不小心输入CTRL+S后,终端没反应了,即没输出,也不响应任何输入。这是因为这个命令会告诉TTY暂停,阻塞所有读写操作,即不转发任何数据,只有按了CTRL+Q后,才会继续。这个功能应该是历史遗留,以前终端和服务器之间没有流量控制功能,所以有可能服务器发送数据过快,导致终端处理不过来,于是需要这样一个命令告诉服务器不要再发了,等终端处理完了后在通知服务器继续。
该命令现在比较常用的一个场景就是用tail -f
命令监控日志文件的内容时,可以随时按CTRL+S让屏幕停止刷新,看完后再按CTRL+Q让它继续刷,如果不这样的话,需要先CTRL+C退出,看完后在重新运行tail -f
命令。
echo
在终端输入字符的时候,之所以我们能及时看到我们输入的字符,那是因为TTY在收到终端发过去的字符后,会先将字符原路返回一份,然后才交给前端进程处理,这样终端就能及时的显示输入的字符。echo就是用来控制该功能的配置项,如果是-echo的话表示disable echo功能。
-tostop
如果你在shell中运行程序的时候,后面添加了&,比如./myapp &
,这样myapp这个进程就会在后台运行,但如果这个进程继续往tty上写数据呢?这个参数就用来控制是否将输出转发给终端,也即结果会不会在终端显示,这里“-tostop”表示会输出到终端,如果配置为“tostop”的话,将不输出到终端,并且tty会发送信号SIGTTOU给myapp,该信号的默认行为是将暂停myapp的执行。
Isyarat berkaitan TTY
Selain SIGINT, SIGTTOU dan SIGWINCHU yang dinyatakan dalam pengenalan konfigurasi di atas, terdapat beberapa isyarat berkaitan TTY
SIGTTIN
Apabila proses latar belakang membaca tty, tty akan menghantar isyarat kepada kumpulan proses yang sepadan Kelakuan lalai adalah untuk menggantung pelaksanaan proses dalam kumpulan proses. Bagaimana untuk meneruskan pelaksanaan proses yang digantung? Sila rujuk SIGCONT dalam artikel seterusnya.
SIGHUP
Apabila hujung tty yang satu lagi digantung, contohnya, sesi ssh diputuskan sambungan, jadi sshd menutup fd yang dikaitkan dengan ptmx, dan kernel akan memberikan tty berkaitan Semua proses hantar isyarat SIGHUP, dan tingkah laku lalai proses selepas menerima isyarat adalah untuk keluar dari proses.
SIGTSTP
Apabila terminal memasuki CTRL Z, tty akan menghantar SIGTSTP ke kumpulan proses bahagian hadapan selepas menerimanya Kelakuan lalainya ialah meletakkan kumpulan proses bahagian hadapan ke dalam back-end dan jeda kumpulan proses pelaksanaan semua proses.
Isyarat yang berkaitan dengan tty boleh ditangkap, dan tingkah laku lalainya boleh diubah suai
Kesimpulan
Artikel ini memperkenalkan fungsi dan Ciri tty biasa, artikel seterusnya akan memperkenalkan secara terperinci id sesi proses, kumpulan proses, kerja, program latar belakang dan sebagainya yang berkait rapat dengan tty, jadi nantikan.
Cadangan berkaitan: "tutorial video linux"