Linux 中的 终端,控制台,TTY,PTY 究竟是什么?它们与进程有什么关系?
控制台是一个直接控制设备的面板 (属于设备的一部分)
计算机设备的控制台:按键 & 指示灯 (键盘 & 显示器)
早期的电子计算机必然有一个控制台
终端是一台独立于计算机的机器,是能够和计算机进行交互的设备
TTY -- 即:TeleType Writer 电传打字机,一种终端设备
以前 TTY 是电传打字机;现在 TTY 已经成为一种标准,其他终端想要和计算机进行交互,就需要遵守 TTY 标准
电传打字机已经淘汰
计算机上的输入设备和显示设备从主机独立出来
控制台与终端的物理表现形式逐渐趋近
计算机开始支持多任务处理
TTY 演变为 Linux 中的抽象概念,对于进程而言 TTY 是一种输入输出设备
用户进程通过系统调用访问 TTY 设备来获取输入、展示输出;而 TTY 设备运行于内核模式,可以与外设进行交互,而外设为了成功的被进程使用,就需要在驱动层面满足 TTY 标准
Linux 有两种工作界面模式,一种是图形界面模式,使用的终端是伪终端;另一种是 命令行(文本)模式,使用的终端是虚拟终端
gnome-terminal 是一个进程,对接 PTY 主设备,可以操控键盘和显卡,bash 也是一个进程,是 shell 的一种类型,对接 PTY 从设备;主设备发送数据后,从设备可以接收到主设备发送的消息,从设备发送数据后,主设备也可以接收到从设备发送的消息,这是一种进程间通信的方法
当我们在命令行中输入 ls 后,bash 去执行 ls 后得到结果,然后将结果发送给 gnome-terminal,gnome-terminal 接收到结果后,会去操控显卡,在命令行中显示结果,这就是使用图形界面的命令行
我们通过 pstree 来查看图形化界面命令行中的进程树,可以看出图形化界面命令行使用的是伪终端
虚拟终端和伪终端的工作模式有较大的差别。但对于shell 进程而说,虚拟终端和伪终端没什么区别,它们都是 tty 设备
创建 PTY 主从设备:master = posix_openpt(O_RDWR);
创建主设备权限:
读写主设备
打开 PTY 从设备:slave = open(path_to_slave, O_RDWR);
读写从设备:
伪终端程序设计
master.c
- #define _XOPEN_SOURCE 600
- #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <string.h>
- #include <unistd.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); // show on screen
- write(master, txbuf, strlen(txbuf)); // keyboard input
- i = 0;
- }
- else
- {
- rxbuf[i++] = rx;
- }
- }
-
- close(master);
- }
- else
- {
- printf("create pty error...\n");
- }
-
- return 0;
- }
slave.c
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <string.h>
- #include <unistd.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);
- }
-
-
- return 0;
- }
程序运行结果如下图所示:
通过打印可以看出,PTY 主从设备可以收到对方发过来的消息
终端必然与进程关联才有意义!那么进程之间除了父子关系,是否还有其他关系?