• Linux 终端与进程


    有趣的问题

    Linux 中的 终端,控制台,TTY,PTY 究竟是什么?它们与进程有什么关系?

    历史回顾:控制台 (Console)

    控制台是一个直接控制设备的面板 (属于设备的一部分)

    计算机设备的控制台:按键 & 指示灯 (键盘 & 显示器)

    早期的电子计算机必然有一个控制台

    历史回顾:终端 (Terminal)

    终端是一台独立于计算机的机器,是能够和计算机进行交互的设备

    TTY -- 即:TeleType Writer 电传打字机,一种终端设备

    以前 TTY 是电传打字机;现在 TTY 已经成为一种标准,其他终端想要和计算机进行交互,就需要遵守 TTY 标准

    历史发展进程

    电传打字机已经淘汰

    计算机上的输入设备和显示设备从主机独立出来

    控制台与终端的物理表现形式逐渐趋近

    计算机开始支持多任务处理

    终端与进程

    TTY 演变为 Linux 中的抽象概念,对于进程而言 TTY 是一种输入输出设备

    用户进程通过系统调用访问 TTY 设备来获取输入、展示输出;而 TTY 设备运行于内核模式,可以与外设进行交互,而外设为了成功的被进程使用,就需要在驱动层面满足 TTY 标准

    各种终端类型

    Linux 有两种工作界面模式,一种是图形界面模式,使用的终端是伪终端;另一种是 命令行(文本)模式,使用的终端是虚拟终端

    内核终端模拟器

    伪终端模型

    伪终端 (gnome-terminal)

    gnome-terminal 是一个进程,对接 PTY 主设备,可以操控键盘和显卡,bash 也是一个进程,是 shell 的一种类型,对接 PTY 从设备;主设备发送数据后,从设备可以接收到主设备发送的消息,从设备发送数据后,主设备也可以接收到从设备发送的消息,这是一种进程间通信的方法

    当我们在命令行中输入 ls 后,bash 去执行 ls 后得到结果,然后将结果发送给 gnome-terminal,gnome-terminal 接收到结果后,会去操控显卡,在命令行中显示结果,这就是使用图形界面的命令行

    我们通过 pstree 来查看图形化界面命令行中的进程树,可以看出图形化界面命令行使用的是伪终端

    虚拟终端和伪终端的工作模式有较大的差别。但对于shell 进程而说,虚拟终端和伪终端没什么区别,它们都是 tty 设备

    伪终端程序设计 (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

    1. #define _XOPEN_SOURCE 600
    2. #include <stdio.h>
    3. #include <stdlib.h>
    4. #include <fcntl.h>
    5. #include <string.h>
    6. #include <unistd.h>
    7. int main()
    8. {
    9. char rx = 0;
    10. char rxbuf[128] = {0};
    11. char txbuf[256] = {0};
    12. int master = 0;
    13. int c = 0;
    14. int i = 0;
    15. master = posix_openpt(O_RDWR); // gnome-terminal
    16. if( master > 0 )
    17. {
    18. grantpt(master);
    19. unlockpt(master);
    20. printf("Slave: %s\n", ptsname(master));
    21. while( (c = read(master, &rx, 1)) == 1 )
    22. {
    23. if( rx == '\r' )
    24. {
    25. rxbuf[i] = 0;
    26. sprintf(txbuf, "from slave: %s\r", rxbuf); // show on screen
    27. write(master, txbuf, strlen(txbuf)); // keyboard input
    28. i = 0;
    29. }
    30. else
    31. {
    32. rxbuf[i++] = rx;
    33. }
    34. }
    35. close(master);
    36. }
    37. else
    38. {
    39. printf("create pty error...\n");
    40. }
    41. return 0;
    42. }

    slave.c

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <fcntl.h>
    4. #include <string.h>
    5. #include <unistd.h>
    6. int main(int argc, char* argv[])
    7. {
    8. int slave = open(argv[1], O_RDWR); // shell
    9. if( slave > 0 )
    10. {
    11. char buf[256] = {0};
    12. char* data = "D.T.Software\r";
    13. int len = strlen(data);
    14. write(slave, data, len);
    15. sleep(1);
    16. len = read(slave, buf, sizeof(buf)-1);
    17. buf[(len > 0) ? len : 0] = 0;
    18. printf("Read: %s\n", buf); // system(...)
    19. close(slave);
    20. }
    21. return 0;
    22. }

    程序运行结果如下图所示:

    通过打印可以看出,PTY 主从设备可以收到对方发过来的消息

    思考

    终端必然与进程关联才有意义!那么进程之间除了父子关系,是否还有其他关系?

  • 相关阅读:
    山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(二十六)- 微服务(6)
    【Java】高效利用异常处理技巧
    AssetBundle检测服务使用指南
    客户心声|腾讯云数据库助力国信证券反洗钱系统分布式改造
    我在Vscode学OpenCV 几何变换(缩放、翻转、仿射变换、透视、重映射)
    第5/100天 阅读笔记
    Java基于springboot+vue的家用电器销售购物商城系统 前后端分离
    Nginx服务之SSL
    配置VUE环境过程中 npm报错的处理方案以及VUE环境搭建过程
    git-新增业务代码分支
  • 原文地址:https://blog.csdn.net/qq_52484093/article/details/133085147