APUE读书笔记-19伪终端(2)
2020-09-28 本文已影响0人
QuietHeart
2、概述
伪终端的意思是,这个终端对于应用程序来说表现像是一个终端,但是实际上它并不是一个真正的终端。下面的图就展示了一个典型的进程使用伪终端的组织结构。
典型的伪终端
进程使用伪终端的典型结构
+----------+ +----------+
| user | fork | user |
| process |-------->| process |
+-----^----+ exec +-----^----+
| |stdin,stdout,stderr
+- - - - - - - - - - - - - - - - - - - - - - - - -+
| | | |
+---------v-------+ +--------v-------+
| | read and write | | read and write | |
| functions | | functions |
| +-----|-----^-----+ +----|------^----+ |
| | | |
| | | +----v------|----+ |
| | | terminal | Kernel
| | | | line dscipline | |
| | +----|------^----+
| | | | | |
+-----v-----|-----+ +----v------|----+
| | pseudo-terminal | | pseudo-terminal| |
| master | | slave |
| +-----|-----^-----+ +----|------^----+ |
| | v |
| | +<-------------+ | |
v |
| +-------------------------->+ |
+- - - - - - - - - - - - - - - - - - - - - - - - -+
- 一般来说,进程打开伪终端主控端(后面用pseudo-terminal master表示),然后调用fork。子进程建立新的会话,打开相应的伪终端从控端(后面用pseudo-terminal slave表示),复制文件描述符号到标准输入、标准输出、标准错误输出,然后调用exec。pseudo-terminal变成子进程的控制终端。
- 对于slave端的用户进程来说,它的标准输入,标准输出,以及标准错误输出是一个终端设备。进程可以对这些文件描述符号调用所有前面描述的终端I/O相关的函数。但是,因为在slave下面没有真正的终端设备,所以不会起作用的那些函数(改变波特率,发送break字符,设置oddparity等),会被忽略。
- 任何写入到master端的内容都会被视作slave端的输入,反之亦然。实际上,所有到达slave端的输入来自pseudo-terminal master上面的用户进程。这个行为看起来就像是一个双向的管道。但是通过slave上面的终端行规范模块,我们可以有除了管道之外更多的能力。
上面的图中的伪终端表现是FreeBSD,Mac OS X, 或者 Linux系统上面的大致情况。后面,我们将要展示如何打开这些设备。
Solaris的伪终端
在Solaris下,伪终端通过使用STREAMS子系统构建。下面的图形列出了Solaris下面的伪终端STREAMS模块的组织结构。两个用虚线框起来的STREAMS模块(ttcompat和pckt)是可选的。pckt和ptem模块用来提供伪终端的语义规范。另外两个模块(ldterm和ttcompat)提供行处理规范。
Solaris下面伪终端的结构
+----------+ +----------+
| user | fork | user |
| process |-------->| process |
+-----^----+ exec +-----^----+
| |stdin,stdout,stderr
+- - - - - - - - - - - - - - - - - - - - - - - - -+
| | | |
+---------v-------+ +--------v-------+
| | stream head | | stream head | |
+-----|-----^-----+ +----|------^----+
| | | | | |
| | +- - v- - - |- - +
| | | . ttcompat . |
| | . STREAMS module .
| | | + - -| - - -^ - -+ |
| | | |
| | | +----v------|----+ |
| | | ldterm |
| | | | STREAMS module | | kernel
| | +----|------^----+
| | | | | |
+- - -v- - -|- - -+ +----v------|----+
| . pckt . | ptem | |
. STREAMS module . | STREAMS module |
| +- - -|- - -^- - -+ +----|------^----+ |
| | | | | |
+-----v-----|-----+ +----v------|----+
| | pseudo-terminal | | pseudo-terminal| |
| master | | slave |
| +-----|-----^-----+ +----|------^----+ |
| | v |
| | +<-------------+ | |
v |
| +-------------------------->+ |
+- - - - - - - - - - - - - - - - - - - - - - - - -+
需要注意的是slave上面的三个STREAMS模块和以前"高级输入输出"中的一个名为"列出stream上的模块名称"的用于网络登陆的代码中的输出是一样。后面我们将会展示如何构建这个结构的STREAMS模块。
现在开始,我们将要通过去掉"read and write functions"来简化前面的"进程使用伪终端的典型结构"图形,或者通过去掉"stream head"简化前面的"Solaris下面伪终端的结构"图形。我们将会使用PTY表示伪终端的简写,把前面"Solaris下面伪终端的结构"的slave PTY之上所有的STREAMS模块放到"terminal line discipline"盒子中。