1. 终端I/O概述
1.1 规范和非规范模式
终端I/O有两种不同的工作模式:
- 规范模式输入处理:对终端输入以行为单位进行处理。对于每个读请求,最多返回一行。
- 非规范模式输入处理:输入字符不装配成行
若不做特殊处理,则终端I/O默认模式是规范模式。处理整个屏幕的程序(如vi编辑器)使用非规范模式。
1.2 特殊输入字符
POSIX.1定义了11个特殊输入字符,例如文件结束符(Ctrl+D)和挂起字符(Ctrl+Z),其中9个可以更改。
1.3 终端设备的输入输出队列
终端设备由位于内核中的终端驱动程序控制。每个终端设备都有一个输入队列和一个输出队列。
大多数UNIX系统在一个称为终端行规程的模块中进行全部的规范处理。可以认为该模块位于读、写函数和实际设备驱动程序之间
1.4 termios结构体
所有可以检测到的和可更改的终端设备属性都包含在termios结构体中
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
struct termios
{
tcflag_t c_iflag; /* 输入标志(终端输入方式) */
tcflag_t c_oflag; /* 输出标志(终端输出方式) */
tcflag_t c_cflag; /* 控制标志(终端硬件控制信息) */
tcflag_t c_lflag; /* 本地标志(驱动程序与用户之间的接口) */
cc_t c_cc[NCCS]; /* 控制字符(特殊字符) */
speed_t c_ispeed; /* 输入波特率 */
speed_t c_ospeed; /* 输出波特率 */
};
https://blog.csdn.net/wumenglu1018/article/details/53098794/
- 输入标志:控制终端输入方式
- 输出标致:控制终端输出方式
- 控制标志:指定终端硬件控制信息
-
本地标志:影响驱动程序与用户之间的接口,控制终端编辑功能(如回显打开关闭、可视的擦除字符、允许终端产生信号)
-
控制字符:用于保存终端驱动程序中的特殊字符,如输入结束符等
1.5 对终端设备进行操作的13个函数
函数 | 说明 |
---|---|
tcgetattr | 获取终端属性(termios结构) |
tcsetattr | 设置终端属性(termios结构) |
cfgetispeed | 获得输入波特率 |
cfgetospeed | 获得输出波特率 |
cfsetispeed | 设置输入波特率 |
cfsetospeed | 设置输出波特率 |
tcdrain | 等待所有输出都被传输 |
tcflow | 挂起传输或接收 |
tcflush | 冲洗未决输入和/或输出 |
tcsendbreak | 发送BREAK字符 |
tcgetpgrp | 获得前台进程组ID |
tcsetpgrp | 设置前台进程组ID |
tcgetsid | 获得控制终端的会话首进程的pid |
与终端设备有关的各函数之间的关系
2. 特殊输入字符
POSIX.1定义了11个在终端输入时要特殊处理的字符,即特殊输入字符。当我们在终端输入这些字符会造成特殊处理,如按下Ctrl+C
会导致向前台进程组的所有进程发送SIGINT信号。
具体见下图
-
在POSIX.1支持的11个特殊输入字符中,其中有9个字符的值可以任意更改。不能更改的两个特殊输入字符是换行符(\n)和回车符(\r)。
-
虽然称这些字符为特殊输入字符,但是STOP(Ctrl+S)和START(Ctrl+Q)在输出时也要进行特殊处理。
-
这些字符中的大多数被终端驱动程序处理之后就被丢弃了,并不会被用户进程读取到。用户能读取到的特殊输入字符只有换行符(NL、EOL、EOL2)和回车符(CR)
-
如果要更改某个特殊输入字符,只需要修改termios结构中c_cc数组的对应项(c_cc每个元素都是unsigned char类型,因此直接赋值为期望的字符即可)。该数组中的元素都用名字作为下标,每个名字都以V开头(见上图中的第三列)。
-
如果要禁用某个特殊输入字符,只需要修改termios结构中c_cc数组的对应项值为_POSIX_VDISABLE。
#define _POSIX_VDISABLE '\0'
示例:禁用中断字符,并将文件结束符设置为Ctrl+B
int main(int argc, char *argv[])
{
struct termios term;
if(isatty(STDIN_FILENO) == 0) exit(0);
tcgetattr(STDIN_FILENO