
(五)tty字符设备(深入理解sshd创建pty的过程)
发布日期:2021-05-08 17:51:05
浏览次数:22
分类:原创文章
本文共 5760 字,大约阅读时间需要 19 分钟。
文章目录
1.tty字符设备
- 在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件(比如:块设备,socket套接字,pipe队列)
- 操作这些不同的类型就像操作文件一样,比如增删改查等
- 块设备支持随机访问,而字符设备只能依据先后顺序来读取数据。最典型的字符设备就是tty
2.tty设备的产生历史
根据史料记载:
An ASR33 Teletype - origin of the abbreviation tty.
tty来源一种电传打印机(teletype),就像这样:
- 敲击键盘输入不同的字符,然后由打印机将字符打印在纸上
- 历史不断在往前发展,出现了计算机之后,计算机模拟了teletype的模式:通过外部终端输入,将输入的字符打印在屏幕上
- 在teletype与计算机之间用串口相连,并且在计算机上通过信号转换(模拟信号转换为数字信号),让计算机能够识别,从而操作计算机
- 由于计算机厂商众多,每个厂商都有自己风格的输入设备,所以计算机为了兼容这些设备,开发了内核tty模块
+-----------------+ | |+--------+ | +-------------+ ||teletype|-----------------> |serial | |+--------+ | |communication| | | +-----+-------+ | | | | | v | | +----------+ | +----------+ | |tty driver| |------->| display | | +----------+ | +----------+ | | |computer | +-----------------+
3.tty设备文件
- 登陆到操作系统(不使用SSH协议,而使用控制台直接登陆),首先查看当前进程号所使用的tty
root@ubuntu:~# tty/dev/pts/4root@ubuntu:~# ll /dev/pts/4crw------- 1 jiwangreal tty 136, 4 Nov 24 13:46 /dev/pts/4当前所使用的是/dev/pts/4,并且pts/4也分配了主设备号与次设备号(关于主设备号与次设备号,请看之前的文章:块设备文件)
- 查看进程打开的描述符
root@ubuntu:~# echo $$2652root@ubuntu:~# ll /proc/2652/fdtotal 0dr-x------ 2 root root 0 Nov 24 13:47 ./dr-xr-xr-x 9 root root 0 Nov 24 13:47 ../lrwx------ 1 root root 64 Nov 24 13:47 0 -> /dev/pts/4lrwx------ 1 root root 64 Nov 24 13:47 1 -> /dev/pts/4lrwx------ 1 root root 64 Nov 24 13:47 2 -> /dev/pts/4lrwx------ 1 root root 64 Nov 24 13:47 255 -> /dev/pts/4进程打开了4个文件描述符,这四个文件描述符都是/dev/tty1,他们的作用分别是:0:标准输入1:标准输出2:标准错误255:这个比较特殊,主要用于当tty重置的时候对0,1,2的一份复制(个人观点是对tty之前的历史信息作为一份复制)
4.ssh登录之后的tty
刚才介绍的都是操作系统提供的控制台登陆之后的情况,如果用ssh服务登陆之后会产生什么情况呢?
首先介绍一个非常重要的概念,伪终端pty:
- pty是一对虚拟的字符设备,提供双向通信。pty一般由master与slave组成
- pty的出现是为了满足现在的登陆需求:网络登陆(ssh登陆、telnet登陆等)、Xwindow等
- 历史上有两套接口标准:分别是BSD与unix98,当前大多数pts都是基于unix98标准来实现的
- unix98的工作流程:
(1)进程对/dev/ptmx调用open(),返回pseudoterminal master(PTM)的文件描述符,并且在/dev/pts下创建pseudoterminal slave(PTS): /dev/pts/0
(2)调用grantpt()修改PTS的文件权限;调用unlockpt()对PTS解锁;最后调用slavename()得到PTS文件名字
(3)此时,PTM与PTS都已经正常打开,并且建立一条通道,两端分别连接PTM与PTS
(4)进程对PTM写的数据可以从PTS读出来,反之亦然
下面的未做验证…因为我用ssh登录的话情况不太一样,看原作者的,了解一下登录过程即可
- 登录
(1)当进程ssh client请求与sshd建立登陆连接的时候,经过TCP握手以及tls握手之后,确认是一个合法的请求,sshd会fork()一个子进程出来专门服务于这条连接
[root@localhost ~]# ps -ef | grep sshdroot 894 1 0 Nov25 ? 00:00:00 /usr/sbin/sshd -Droot 3126 894 0 Nov25 ? 00:00:00 sshd: root@pts/0
(2)子进程2768对/dev/ptmx调用open(),得到PTM的文件描述符以及PTS的文件名
#这里使用strace跟踪sshd主进程和它创建的子进程,然后打开另外一个shell登陆服务器[root@localhost ~]# strace -p 894 -ff -o sshdstrace: Process 894 attachedstrace: Process 3126 attachedstrace: Process 3127 attachedstrace: Process 3128 attachedstrace: Process 3129 attachedstrace: Process 3130 attachedstrace: Process 3131 attachedstrace: Process 3132 attachedstrace: Process 3133 attachedstrace: Process 3134 attachedstrace: Process 3135 attachedstrace: Process 3136 attachedstrace: Process 3137 attachedstrace: Process 3138 attachedstrace: Process 3139 attachedstrace: Process 3140 attached[root@localhost ~]# grep ptmx ./sshd.*./sshd.3126:open("/dev/ptmx", O_RDWR) = 8shd894创建了一个子进程3126用来处理这条TCP连接。进程对/dev/ptmx调用open(),得到PTM的文件描述符8
(3)子进程3126在/dev/pts下创建了一个字符设备文件/dev/pts/0,8与/dev/pts/0成为一对master/slave
(4)子进程3126会再fork()一个子进程3128,子进程3128打开/dev/pts/0 3个描述符(标准输入,标准输出,标准错误),并且执行操作系统默认的shell(本文中bash)
[root@localhost ~]# ps -ef | grep 3126root 3126 894 0 03:16 ? 00:00:00 sshd: root@pts/0root 3128 3126 0 03:16 pts/3 00:00:00 -bash[root@localhost ~]# ls -l /proc/3128/fdtotal 0lrwx------ 1 root root 64 Nov 26 03:16 0 -> /dev/pts/0lrwx------ 1 root root 64 Nov 26 03:16 1 -> /dev/pts/0lrwx------ 1 root root 64 Nov 26 03:16 2 -> /dev/pts/0lrwx------ 1 root root 64 Nov 26 03:22 255 -> /dev/pts/0
- 至此,通信流程大概是这样:
+----------------++------------+ | || ssh client +---------->| sshd |+----+-------+ | | | +--------+-------+ | | | | | fork() | | | | | v | +----+-----+ fork() +----------+ +-----+ +---------------------->|pid: 3126 |-------------->|pid: 3128 |----->|bash | +-+--------+ +----------+ +-----+ | ^ | | +-------+ | +------|--------------------------------+ | | | +-----------+ | | | v | | | | | +---------+ fd=8 +-----------+ | | | |/dev/ptmx|---------->|/dev/pts/0 |--------+ | +---------+ +-----------+ | | | | | | +-----------+ | +---------------------------------------+步骤如下:(1)当ssh client发出一个ls命令,通过TCP连接来到3126,3126将ls写入PTM文件描述符8(2)/dev/ptmx查询到关联记录 PTM:8对应PTS:/dev/pts/0,把ls转发到/dev/pts/0当中(3)3128从0 -> /dev/pts/0中读取之后执行ls(4)ls返回结果之后写入1 -> /dev/pts/0,然后根据关联记录回写到/dev/ptmx(5)3126从/dev/ptmx读取之后返回到ssh client
参考:
https://www.cnblogs.com/MrVolleyball/p/10024540.html
发表评论
最新留言
路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年03月23日 13时51分15秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
CODING 敏捷实战系列课第三讲:可视化业务分析
2021-05-09
工作动态尽在掌握 - 使用 CODING 度量团队效能
2021-05-09
CODING DevOps 深度解析系列第二课报名倒计时!
2021-05-09
数据结构第八节(图(下))
2021-05-09
基于Mustache实现sql拼接
2021-05-09
POJ 2260 Error Correction 模拟 贪心 简单题
2021-05-09
gRPC在 ASP.NET Core 中应用学习(一)
2021-05-09
@SuppressWarnings 用法
2021-05-09
看完你就明白的锁系列之锁的状态
2021-05-09
看完这篇操作系统,和面试官扯皮就没问题了
2021-05-09
我的价值观
2021-05-09
一文详解 Java 并发模型
2021-05-09
值类型与引用类型(中)
2021-05-09
MSSQL 2005 数据库变成可疑状态
2021-05-09
QBlog V2.5 源码开放下载(ASP.NET 番外系列之开端)
2021-05-09
秋色园引发CPU百分百命案的事件分析与总结
2021-05-09
安装jdk并配置环境变量
2021-05-09
稀疏数组
2021-05-09
js的严格模式
2021-05-09
idea的安装和无限期试用
2021-05-09