《UNIX环境高级编程》十八终端I/O读书笔记

1、综述

终端I/O有两种不同的工作模式:
(1)规范模式输入处理。在这种模式中,对终端输入以行为单位进行处理。对于每个读请求,终端驱动程序最多返回一行。
(2)非规范模式输入处理。输入字符不装配成行。

可以认为终端设备是由通常位于内核中的终端驱动程序控制的。每个终端设备都有一个输入队列和一个输出队列:
这里写图片描述

大多数UNIX系统在一个称为终端行规程的模块中进行全部的规范处理。这个模块位于内核通用读、写函数和实际设备驱动程序之间。
这里写图片描述

所有可以检测和更改的终端设备特性都包含在termios结构中。该结构定义在头文件<termios.h> 中。

struct termios {
tcflag_t  c_iflag;
tcflag_t  c_oflag;
tcflag_t  c_cflag;
tcflag_t  c_lflag;
cc_t      c_cc[NCCS];   /*control characters*/
};

输入标志通过终端设备驱动程序控制字符的输入,输出标志则控制驱动程序输出,控制标志影响RS-232串行线,本地标志影响驱动程序和用户之间的接口。
这里写图片描述

这里写图片描述

2、特殊输入字符

这里写图片描述
这里写图片描述
注:换行符和回车符(\n和\r)不能更改,其他特殊字符可以任意更改。
为了更改,只需要修改termios结构中c_cc数组的相应项。该数组中的元素都用名字作为下标进行引用,每个名字都以字母V开头。
若将c_cc数组中的某项设置为_POSIX_VDISABLE的值,则禁止使用相应特殊字符。

下面较2详细地说明各个特殊字符(特殊输入字符):
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

3、获得和设置终端属性

为了获得和设置termios结构,可以调用tcgetattr和tcsetattr函数。

#include <termios.h>
int tcgetattr(int fd,struct termios *termptr);
int tcsetattr(int fd,int opt,const struct termios *termptr);
//若成功,返回0;若出错,返回-1

注:
(1)因为这两个函数只对终端设备进行操作,所以若fd没有引用终端设备则出错返回-1,errno设置为ENOTTY。
(2)tcsetattr函数如果执行了任意一种所要求的动作,即使未能执行所有要求的动作,它也返回OK。因此在调用tcsetattr设置所希望的属性后,需调用tcgetattr,然后将实际终端属性与所希望的属性相比较,以检测两者是否有区别。

参数opt使我们可以指定在什么时候新的终端属性才起作用:
TCSANOW:更改立即发生。
TCSADRAIN:发送了所有输出后更改才发生。若更改输出参数则应使用此选项。
TCSAFLUSH:发送了所有输出后更改才发生。更进一步,在更改发生时未读的所有输入数据都被丢弃(冲洗)。

4、终端选项标志

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

5、波特率函数

大多数终端设备对输入和输出使用同一波特率,但只要硬件许可,可以将它们设置为两个不同值。

#include <termios.h>
speed_t cfgetispeed(const struct termios *termptr);
speed_t cfgetospeed(const struct termios *termptr);
//返回波特率值
int cfsetispeed(struct termios *termptr,speed_t speed);
int cfsetospeed(struct termios *termptr,speed_t speed);
//若成功,返回-;若出错,返回-1

speed参数:B50、B75、B110、B134、B200、B300、B600、B1200、B1800、B2400、B4800、B9600、B19200、B38400

在调用两个cfget函数中的任意一个之前,要先用tcgetattr获得设备的termios结构。与此类似,在调用两个cfset函数中的任意一个之后,要做的就是在termios结构中设置波特率。为使这种更改影响到设备,应当调用tcsetattr函数。

6、行控制函数

#include <termios.h>
int tcdrain(int fd);
int tcflow(int fd,int action);
int tcflush(int fd,int queue);
int tcsendbreak(int fd,int duration);
//若成功,返回-;若出错,返回-1

tcdrain函数等待所有输出都被传递。
tcflow函数用于对输入和输出流控制进行控制。action参数必定是下列4个值之一:
TCOOFF:输出被挂起。
TCOON:重新启动以前被挂起的输出。
TCIOFF:系统发送一个STOP字符,这将使终端设备停止发送数据。
TCION:系统发送一个STATRT字符,这将使终端设备恢复发送数据。

tcflush函数冲洗(抛弃)输入缓冲区(其中的数据是终端驱动程序已接收到,但用户尚未读取的)或输出缓冲区(其中的数据是用户程序已经写入,当尚未被传递的)。queue参数必定是下列3个常量之一:
TCIFLUSH:冲洗输入队列。
TCOFLUSH:冲洗输出队列。
TCIOFLUSH:冲洗输入队列和输出队列。

tcsendbreak函数在一个指定的时间区内发送连续的0值位流。

7、终端标志

确定控制终端的名字:

#include <stdio.h>
char *ctermid(char *ptr);
//若成功,返回指向控制终端名的指针;若出错,返回指向空字符串的指针

如果文件描述符引用一个终端设备,则isatty返回真。ttyname返回的是在该文件描述符上打开的终端设备的路径名:

#inlcude <unistd.h>
int isatty(int fd);
//若为终端设备,返回1;否则,返回0
char *ttyname(int fd);
指向终端路径名的指针;若出错,返回NULL

8、规范模式

规范模式很简单:发一个读请求,当一行已经输入后,终端驱动程序即返回。以下几个条件造成读返回:
- 所请求的字节数已读到时,读返回。
- 当读到一个行定界符时,读返回。(NL、EOL、EOL2、EOF、CR)
- 如果捕捉到信号,并且该函数不再自动重启,则读也返回。

9、非规范模式

可以通过关闭termios结构中c_flags字段的ICANON标志来指定非规范模式。在非规范模式中,输入数据不装配成行,不处理下列特殊字符:ERASE、KILL、EOF、NL、EOL、EOL2、CR、REPRINT、STATUS和WERASE。

当已读了指定量的数据后,或者已经超过了给定量的时间后,即通知系统返回。这种技术使用了termios结构中c_cc数组的两个变量:MIN和TIME。c_cc数组中的这两个元素的下标名为VMIN和VTIME。
这里写图片描述

10、终端窗口大小

struct winsize{
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel;
unsigned short ws_ypixel;
};
  • 用ioctl的TIOCGWINSZ命令可以取此结构的当前值。(ioctl(fd,TIOCGWINSZ,(char *)&winsize)
  • 用ioctl的TIOCSWINSZ命令可以将此结构的新值存储到内核中。如果此新值与存储在内核中的当前值不同,则前台进程组会收到SIGWINCH信号(默认动作忽略)。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值