详解控制台与终端
乏味的问题:Linux 的终端,控制台,TTY, PTY 到底是什么?它们与过程有什么关系?
历史回顾:控制台
- 控制台是一个间接管制设施的面板(属于设施的一部分)
- 计算机设备的控制台:按键 & 指示灯 (键盘 & 显示器)
- 晚期的电子计算机必然有一个控制台
历史回顾:终端 (Terminal)
- 终端是一台独立于计算机的机器,是可能用来和计算机进行交互的设施
TTY -- 即:TeleType Writer 电传打字机,一种终端设备
历史倒退过程。。。
- 电传打字机曾经淘汰
- 计算机上的输出设施和显示设施从主机独立进去
- 控制台与终端的物理表现形式逐步趋近
- 计算机开始反对多任务处理
- 。。。
终端与过程
- TTY 演变为 Linux 中的抽象概念,对于过程而言,TTY是一种输入输出设施
虚构终端与伪终端
各种终端类型
类型 | 阐明 | |
虚构终端(Virtual Terminal) | 将这一套键盘和显示器映射为 6 个终端设备 | /dev/tty1~tty6 tty0指代以后应用的终端 (CLI虚构出) |
串口终端(Serial Port Terminal) | 将连贯到窗口的外设看看作终端设备 | /dev/ttyS1,... |
终端模拟器(Terminal Emulator) | 终端模拟程序(狭义) / 内核模仿模块(侠义) | Putty, MobaXTERM, 内核模块,伪终端 |
伪终端(Pseudo Terminal) | 运行在用户模式的终端模拟程序,分为主设施(pty master)和从设施(pty slave) | /dev/ptmx(主), /dev/pts/3(从), ... |
内核终端模拟器
伪终端模型
伪终端(gnome-terminal)
伪终端
tiansong@tiansong:~$ pstree -A -p -s $$systemd(1)---systemd(968)---gnome-terminal(1885)---bash(1973)---pstree(2052)
虚构终端
ubuntu 由 GUI 切换到 CLI : CTRL + ALT +F3tiansong@tiansong:~$ pstree -A -p -s $$systemd(1)---login(2064)---bash(2118)---pstree(2125)ubuntu 由 CLI 切换到 GUI : CTRL + ALT +F1
伪终端程序设计原理
站在 shell 角度的总结:1. shell 面对的只有 TTY 设施,而 TTY 是 Linux 中的抽象概念,因而须要一个具体的模块来反对这个形象的概念2. 对于虚构终端,反对这个概念的模块就是终端模拟器(内核模块,运行于内核模式),能够间接应用键盘、显卡驱动进行输入输出3. 对于伪终端,创立主、从设施,其中 shell 过程对接的是从设施,主设施对接用户过程 gnome-terminal (实质是 GUI 应用程序)
伪终端程序设计(master)
- 创立 PTY 主从设施:
master = posix_openpt(O_RDWR);
获取主设施权限:
grantpt(master);
// 获取设施应用权限unlockpt(master);
// 解锁设施,为读写做筹备
读写主设施
c = read(master, &rx, 1);
len = write(master, txbuf, strlen(txbuf));
伪终端程序设计(slave)
- 关上 PTY 从设施,
slave = open(path_to_slave, O_RDWR);
读写设施:
write(slave, "Delphi\r", 7);
read(slave, buf, sizeof(buf) - 1);
实战伪终端程序设计
master.c
#define _XOPEN_SOURCE 600#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <string.h>#include <unistd.h>#include <fcntl.h>int main(){ char rx = 0; char rxbuf[128] = {0}; char txbuf[256] = {0}; int master = 0; int c = 0; int i = 0; master = posix_openpt(O_RDWR); // 连贯主设施,等同于 gnome-terminal if (master > 0) { grantpt(master); unlockpt(master); printf("Slave: %s\n", ptsname(master)); while ((c = read(master, &rx, 1)) == 1) { if (rx == '\r') { rxbuf[i] = 0; sprintf(txbuf, "from slave: %s\r", rxbuf); // 等同于屏幕输入 write(master, txbuf, strlen(txbuf)); // 等同于键盘输入 } else { rxbuf[i++] = rx; } } } else { printf("create pty error...\n"); } return 0;}
tiansong@tiansong:~/Desktop/linux$ gcc master.c -o master.outtiansong@tiansong:~/Desktop/linux$ ./master.out // 不终止Slave: /dev/pts/0
slave.c
#define _XOPEN_SOURCE 600#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <string.h>#include <unistd.h>#include <fcntl.h>int main(int argc, char *argv[]){ int slave = open(argv[1], O_RDWR); // 等同于 shell if (slave > 0) { char buf[256] = {0}; char *data = "D.T.Software\r"; int len = strlen(data); write(slave, data, len); sleep(1); len = read(slave, buf, sizeof(buf) - 1); buf[(len > 0) ? len : 0] = 0; printf("Read: %s\n", buf); // system(...) close(slave); } else { } return 0;}
tiansong@tiansong:~/Desktop/linux$ gcc slave.c -o slave.outtiansong@tiansong:~/Desktop/linux$ ./slave.out /dev/pts/0 // 新终端执行Read: from slave: D.T.Software
终端必然与过程关联才有意义!那么,过程之间除了父子关系,是否还有其它关系?