在Linux系统中,终端是一种字符型设备,它有多种类型,通常使用 tty 来简称各种类型的终端设备。tty 是 Teletype 的缩写,Teletype 是最早出现的一种终端设备,很像电传打字机,是由 Teletype 公司生产的。Linux 中包含如下几类终端设备。
1. 串行端口终端(/dev/ttySn)
串行端口终端(Serial Port Terminal)是使用计算机串行端口连接的终端设备。计算机把每个串行端口都看作是一个字符设备。这些串行端口所对应的设备名称是 /dev/ttyS0(或 /dev/tts/0)、/dev/ttyS1(或 /dev/tts/1)等,设备号分别是 (4, 0)、(4, 1)等。
在命令行上把标准输出重定向到端口对应的设备文件名上就可以通过该端口发送数据,例如,在命令行提示符下键入: echo test > /dev/ttyS1 会把单词 “test” 发送到连接在 ttyS1 端口的设备上。
目前 USB-串口转换器也已经非常常用,其对应设备节点通常为 /dev/ttyUSB0、/dev/ttyUSB1等。
2、伪终端(/dev/pty/)
伪终端 pty (Pseudo Terminal)是成对的逻辑终端设备,并存在成对的设备文件,如 /dev/ptyp3 和 /dev/ttyp3,它们与实际物理设备并不直接相关。如果一个程序把 ttyp3 看作是一个串行端口设备,则它对该端口的读/写操作会反应在该逻辑终端设备对应的 ttyp3 上,而ttyp3 看作是一个串行端口设备,则它对该端口的读/写操作会反应在该逻辑终端设备对应的 ttyp3 上,而 ttyp3 则是另一个程序用于读写操作的逻辑设备。这样,两个程序就可以通过这种逻辑设备进行互相交流,使用 ttyp3 的程序会认为自己正在与一个串行端口进行通信。
以 telnet 为例,如果某人在使用 telnet 程序连接到 Linux 系统,则 telnet 程序就可能会开始连接到设备 ptyp2 上,而此时一个 getty 程序会运行在对应的 ttyp2 端口上。当 telnet 从远端获取了一个字符时,该字符就会通过 ptyp2 、ttyp2 传递给 getty 程序,而 getty 程序则会通过 ttyp2、ptyp2 和 telnet 程序返回 “login:” 字符串信息。这样,登录程序与 telnet 程序就通过伪终端进行通信。通过使用适当的软件,可以把两个或多个伪终端设备连接到同一个物理串行端口上。
而目前的 Linux 版本常采用 pts (pseudo-terminal slave) 与 ptmx (pseudo-terminal master)配合的方法来实现 pty。目录 /dev/pts 是一个类型为 devpts 的文件系统,并且可以在被加载文件系统列表中看到。 /dev/ptmx 是一个主设备号为 5,次设备号为 2 的字符设备,它被用于创建一个 master/slave 对。当某进程打开 /dev/ptmx 的时候,它将得到一个 master 的文件描述符,每个被打开的文件描述符对应一个独立的 master,而且对应一个 pts,将该文件描述符作为参数传入 ptsname 可以得到 pts 的路径。
3、控制终端(/dev/tty)
如果当前进程有控制终端(Controlling Terrminal)的话,那么 /dev/tty 就是当前进程的控制终端的设备特殊文件。可以使用命令 ps -ax 来查看进程与哪个控制终端相连,使用命令 "tty" 可以查看它具体对应哪个实际终端设备。/dev/tty 有些类似于到实际所使用终端设备的一个 link,例如:
[root@jz4775dev]# ps ax PID TTY STAT TIME COMMAND 1 ? Ss 0:02 /sbin/init 2 ? S 0:00 [kthreadd] 3 ? S 0:24 [ksoftirqd/0] 5 ? S< 0:00 [kworker/0:0H]168 ? S 0:01 [jbd2/sda1-8] 169 ? S< 0:00 [ext4-rsv-conver] 170 ? S< 0:00 [kworker/1:1H] 284 ? S< 0:00 [kworker/3:1H] 312 ? S 0:00 upstart-udev-bridge --daemon 321 ? S< 0:00 [kworker/0:1H] 326 ? Ss 0:00 /lib/systemd/systemd-udevd --daemon 419 ? Ss 0:00 dbus-daemon --system --fork 433 ? S< 0:00 [rpciod] 459 ? S< 0:00 [nfsiod] 491 ? Ss 0:00 rpc.idmapd1193 ? Ssl 0:12 NetworkManager 1206 ? Sl 0:00 /usr/lib/policykit-1/polkitd --no-debug 1331 tty4 Ss+ 0:00 /sbin/getty -8 38400 tty4 1335 tty5 Ss+ 0:00 /sbin/getty -8 38400 tty5 1336 ? Ssl 0:10 thermald --no-daemon --dbus-enable 1346 tty2 Ss+ 0:00 /sbin/getty -8 38400 tty2 1347 tty3 Ss+ 0:00 /sbin/getty -8 38400 tty3 1351 tty6 Ss+ 0:00 /sbin/getty -8 38400 tty6 1410 ? Ss 0:00 /usr/sbin/sshd -D 1412 ? Ss 0:00 atd 1416 ? Ss 0:00 /usr/sbin/xinetd -dontfork -pidfile /var/run/xinetd.pid -stayalive -inetd_compat -inetd_ipv6 1418 ? Ss 0:01 cron 1419 ? Ss 0:54 /usr/sbin/irqbalance
内核线程(如 kthreadd)和 用户空间的守护进程(如 udevd)是没有控制终端的,因此其 tty 栏目标注的是“?”。
4、控制台终端(/dev/ttyn, /dev/console)
在 UNIX 系统中,计算机显示器通常被称为控制台终端(console)。它仿真了类型为 Linux 的一种终端(TERM=Linux),并且有一些设备特殊文件与之相关联:tty0、tty1、tty2等。当用户在控制台上登录时,使用的是 tty1。使用 Alt+[F1~F6]组合键时,我们就可以切换到 tty2、tty3等上面去。tty1~tty6 等称为虚拟终端,而 tty0 则是当前所使用虚拟终端的一个别名,系统所产生的信息会发送到该终端上。因此不管当前正在使用哪个虚拟终端,系统信息都会发送到控制台终端上。用户可以登录到不同的虚拟终端上去,因而可以让系统同时有几个不同的会话期存在。只有系统或超级用户 root 可以向 /dev/tty0 进行写操作。
在 Linux 中,可以在系统启动命令行里指定当前的输出终端,格式如下:
console=device,options
device 指代的是终端设备,可以是 tty0(前台的虚拟终端)、ttyX(第 X 个虚拟终端)、ttySX(第 X 个串口)、lp0(第一个并口)等。
options 指代对 device 进行的设置,它取决于具体的设备驱动。对于串口设备,参数用来定义为:
波特率、校验位、位数,格式为 BBBBPN,其中 BBBB 表示波特率,P 表示校验(n/o/e),N 表示位数,默认 options 是 9600n8。
用户可以在内核命令行中同时设定多个 console,这样输出将会在所有的 console 上显示,而当用户调用 open() 打开 /dev/console 时,最后一个 console 将会返回作为当前值。例如:
console=ttyS1, 9600 console=tty0
定义了两个 console,而调用 open() 打开 /dev/console 时,将使用虚拟终端 tty0。但是内核消息会在 tty0 VGA 虚拟终端和串口 ttyS1上同时显示。简单地说,我们可以把 /dev/console 看作内核控制台的 tty 文件接口,设备号为 0x0501,当对其调用 tty_open() 时,它会转义为实际的终端设备。
通过查看/proc/tty/drivers 文件可以获知什么类型的 tty 设备存在以及什么驱动被加载到内核,这个文件包括一个当前存在的不同 tty 驱动的列表,包括驱动名、缺省的节点名、驱动的主编号、这个驱动使用的次编号范围,以及 tty 驱动的类型。例如,下面给出了一个 /proc/tty/drivers 文件的例子:
[root@jz4775dev]# cat /proc/tty/drivers /dev/tty /dev/tty 5 0 system:/dev/tty /dev/console /dev/console 5 1 system:console /dev/ptmx /dev/ptmx 5 2 system /dev/vc/0 /dev/vc/0 4 0 system:vtmaster ttyprintk /dev/ttyprintk 5 3 console serial /dev/ttyS 4 64-111 serial pty_slave /dev/pts 136 0-1048575 pty:slave pty_master /dev/ptm 128 0-1048575 pty:master unknown /dev/tty 4 1-63 console