【转】浅析terminal创建时ptmx和pts关系

本文深入解析了Ubuntu系统中创建terminal终端时的pts文件系统机制,详细阐述了如何通过cat命令观察数据流向,并解释了在不同终端同时访问同一pts文件时的数据争抢现象。通过实验演示,清晰地展现了正常流程与异常情况下的数据处理过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


我们打开一个terminal,那么将会在devpts文件系统/dev/pts下创建一个对应的pts字符文件,
该pts字符文件节点直接由/dev/ptmx节点的驱动函数ptmx_open()
调用devpts_pty_new(tty->link)
[tty对应ptmx,tty->link对应/dev/pts/xxx,那么tty->link->link又对应回ptmx
同样ptm_driver->other等于pts_driver,pts_driver->other等于ptm_driver]主动创建,
而非通过netlink的udev或者hotplug配合创建[luther.gliethttp]

1.首先我们打开3个新的terminal终端
使用who am i查询当前终端对应的pts号
luther@gliethttp:~$ who am i
luther   pts/3        2009-07-03 09:05 (:0.0)
luther@gliethttp:~$ who am i
luther   pts/4        2009-07-03 09:08 (:0.0)
luther@gliethttp:~$ who am i
luther   pts/5        2009-07-03 09:08 (:0.0)
他们分别对应pts 3,4和5.
2.在pts/4终端中执行如下命令
luther@gliethttp:~$ cat /dev/pts/3
llllllllls
3.在pts/3终端中输入平常的命令ls
你会发现输入的数据并不能被完全显示,而2步骤中运行的cat  /dev/pts/3
命令确出现了不完整命令,这是怎么回事呢,接下来我们讲一讲该现象背后的故事[luther.gliethttp].
luther@gliethttp:~$ l
4.讲讲现象背后的故事
当ubuntu系统创建一个新的terminal时(比如上面的pts/3)
4.1 首先执行ptm = open('/dev/ptmx',...)操作
4.2 接下来fork(),然后child将打开'/dev/pts/3',dup2到0,1和2句柄上,随后执行execl启动一个shell.
pts = open('/dev/pts/3',...);
dup2(pts, 0); // 对应lib库中stdin
dup2(pts, 1); // 对应lib库中stdout
dup2(pts, 2); // 对应lib库中stderr
close(pts);
execl("/system/bin/sh", "/system/bin/sh", NULL);
// 这样sh输入数据将全部来自pts,
// sh的输出数据也都全部输送到pts,也就直接送到了打开ptmx的新terminal中.
4.3 新terminal将启动GUI,捕获按键数据,然后写入ptm,这样pts将收到数据,进而sh将从stdin中获得数据,
于是sh将作进一步运算,将结果送给stdout或stderr,进而送给pts,于是ptm获得数据,然后terminal的GUI
将数据显示出来.

具体流程图如下[luther.gliethttp]:
terminal捕获到key按键值 <--> ptm <--> pts/3 <--> stdin <--> shell读到数据
shell数据结果 <--> stdout <--> pts/3 <--> ptm <--> terminal显示
4.4 好了,正常的启动流程图已经有了,来看看,我们试验时数据出现显示异常的现象背后到底是怎么发生的.
与上面正常流程不同的时,我们在另外一个地方执行了cat.

这种情况下的流程图为[luther.gliethttp]:
terminal <--> ptm <--> pts/3 <------> shell
|
<------> 运行在pts/4上的 cat /dev/pts/3
很明显terminal发送数据到pts/3之后,
因为有2个独立的进程都在等待pts/3的数据,所以他们之间就发生了对pts/3数据抢夺现象,
因为linux内核调度器根据当时情况随时都会将他们中的一个调出或者调入,因此数据
就出现了一部分被送到了pts/4的cat命令,另一部分被送到了shell,
因为shell具有回显能力,shell将它接收到的所有字符串一一回显给terminal,所以terminal显示
到的数据就是shell与cat命令争抢数据时,shell自己抢到的数据,
而pts/4上显示的数据就是cat命令抢到的数据[luther.gliethttp]

比如我们仍然在pts/4上执行cat命令,然后我们在pts/5上执行echo命令
luther@gliethttp:~$ who am i
luther   pts/5        2009-07-03 09:08 (:0.0)
luther@gliethttp:~$ echo 'luther.gliethttp' >/dev/pts/3
这时pts/3对应的terminal将完全显示'luther.gliethttp'字符串,因为没有人和ptm争抢数据[luther.gliethttp].
4.5 在pts/3自己所在terminal中执行cat回是什么现象呢,我么继续看看
luther@gliethttp:~$ cat /dev/pts/3
ls
ls
pwd
pwd
可以看到,输入ls回车之后,显示了2个ls,其中1个ls数据是cat命令自己回显出来的,
另外一个ls就来自/dev/pts/3文件,那这是怎么回事呢,原因是这样的,
cat和terminal都能获得键盘数据,cat将键盘数据直接回显到terminal上,
而terminal捕获的数据将通过ptm发送到pts/3,而cat自己又在等待pts/3的数据,所以
cat将从pts/3上再次读取到ptm发送过来的数据,再一次显示到terminal上,
那同样是cat pts/3,为什么就不一样呢,通过strace发现,如果在
terminal中直接调用库函数execve()执行另外一个shell命令,那么sh自身将停止对stdin进行数据读取,
只是等待shell命令退出,数据读取操作权完全交给被执行的shell命令(cat),
所以cat这时0,1,2都是对应pts/3,因为cat /dev/pts/3命令需要打开文件,
所以fd = open('/dev/pts/3',...)之后,fd数值将等于3,这样cat /dev/pts/3他的
0,1,2和3这4个句柄都对应pts/3节点[0为stdin,1为stdout,2为stderr]
所以读取pts/3的进程只有了一个,没有人和他争数据了,当然cat能够完全获得数据了,呵呵[luther.gliethttp]
<think>好的,用户现在想了解Linux终端与其他终端或环境之间的区别。之前的问题是关于如何在Linux终端中编辑代码并添加注释,现在他们向更基础的概念,即终端本身的区别。我需要结合之前的引用内容来回答这个问题。首先,用户提供的引用[1][2]提到了终端Terminal)与控制台(Console)的区别,以及伪终端(Pseudo-Terminal)的概念。引用[3][4]涉及终端的配置使用方法。用户现在的问题是明确询问Linux Terminal与其他终端区别,可能需要比较物理终端、虚拟终端、伪终端、其他操作系统的终端,以及图形界面终端模拟器。我需要先理清各个术语的定义。根据引用[1],传统终端Terminal)是物理设备,而控制台(Console)是直接连接到计算机的物理终端。现代Linux中的终端多为虚拟终端(如tty1-6)终端(如SSH或GUI中的终端模拟器)。引用[2]提到/dev/pts是伪终端设备目录,用于软件模拟的终端会话。接下来,需要区分LinuxTerminal与其他环境中的终端,比如Windows的命令提示符或PowerShell,或者macOS的终端应用。这些虽然都是命令行界面,但底层实现、支持的shell、命令语法工具有所不同。另外,用户可能还关心终端模拟器(如GNOMETerminal)与真实终端区别,或者与嵌入式系统终端的差异。需要指出LinuxTerminal的特点,比如多用户支持、多任务处理、shell的多样性、脚本能力等。还要考虑用户可能的实际需求,比如为什么需要了解这些区别,可能是为了跨平台开发、系统管理或学习Linux特性。因此,回答需要结构清晰,分点说明不同之处,并给出实际例子,如引用[4]中的NOILinux Terminal使用指令,展示Linux终端的具体操作。最后,生成相关问题要围绕用户可能进一步探索的方向,比如不同终端之间的兼容性、如何选择适合的终端环境、跨平台工具的使用等。</think>### Linux终端与其他终端区别分析 #### 一、核心概念定义 1. **Linux终端(Terminal)** - 本质是**文本输入/输出环境**,通过`/dev/tty`或`/dev/pts`设备实现交互[^1][^2] - 支持多用户并发访问(如通过SSH创建多个伪终端会话) - 典型特征: $$ \text{终端会话} = \text{终端设备} + \text{Shell解释器} + \text{进程组控制} $$ 2. **其他终端类型** | 类型 | 特点 | 示例 | |---------------------|----------------------------------------------------------------------|-----------------------------------| | 物理控制台(Console) | 直接连接主机的物理设备(如服务器本地键盘+显示器)[^1] | 服务器维护终端 | | Windows终端 | 基于CMD/PowerShell的封闭环境,不支持原生POSIX命令 | cmd.exe, Windows Terminal | | 嵌入式系统终端 | 通过UART/GPIO实现的低层通信接口 | 树莓派串口调试终端 | | IDE集成终端 | 依赖宿主系统的功能受限模拟环境 | VS Code内置终端 | #### 二、功能差异对比 1. **多任务支持** - Linux终端原生支持`jobs`命令管理后台进程(如`gcc main.c &`后台编译[^4]) - Windows终端需依赖第三方工具实现类似功能 2. **脚本能力** ```bash # Linux终端支持管道符复杂重定向 find . -name "*.cpp" | xargs grep "printf" 2>&1 | tee log.txt ``` - 其他终端(如Windows CMD)的管道功能存在语法限制 3. **环境配置** - Linux通过`.bashrc`实现个性化配置(如修改PS1变量[^3]): $$ \text{PS1} = "\e[32m\u@\h:\w\$ \e[0m" $$ - Windows终端依赖注册表或GUI设置 #### 三、技术实现差异 1. **设备驱动层** - Linux采用`tty`子系统管理终端I/O,通过行规则(line discipline)处理特殊字符[^2] - 其他系统(如macOS)使用相似机制但实现细节不同 2. **伪终端(PTS)架构** ```mermaid graph LR A[终端模拟器] --> B[/dev/ptmx] B --> C[主设备号5] C --> D[从设备/dev/pts/N] D --> E[Shell进程] ``` 该架构支持SSH等网络终端会话[^2] #### 四、典型应用场景 1. **开发调试** - 使用`gdb`进行代码调试(如设置断点`b 38`[^4]) - 实查看系统资源:`top`命令 2. **系统管理** ```bash # 批量注释代码文件 sed -i '10,20s/^/#/' *.py # 引用自用户历史问题 ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值