终端I/O有两种不同的工作模式:

(1)规范模式:输入以行单位进行处理,每个读请求也最多返回一行。

(2)非规范模式:输入字符不装配成行。

终端设备是由通常位于内核中的终端驱动程序控制的。每个终端设备都有一个输入队列和一个输出队列。

  • 如果打开了回显,输入队列和输出队列之间有一个隐含的连接
  • 输入队列有一个MAX_INPUT的有限值
  • 还有一个MAX_CANON,限制输入行的最大字节数
  • 输出队列也是有限的,但是当它快要满的时候,内核会让它休眠,直到有可用空间

终端行规程(terminal line discipline)的模块中进行全部的规范处理。

所有可以检测和更改的终端设备特性都在termios结构中

#include <termios.h>

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

c_cflag支持的常量名称
CBAUD 波特率的位掩码
B0 0波特率(放弃DTR)
B1800 1800波特率
B2400 2400波特率
B4800 4800波特率
B9600 9600波特率
B19200 19200波特率
B38400 38400波特率
B57600 57600波特率
B115200 115200波特率
EXTA 外部时钟率
EXTB 外部时钟率
CSIZE 数据位的位掩码
CS5 5个数据位
CS6 6个数据位
CS7 7个数据位
CS8 8个数据位
CSTOPB 2个停止位(不设则是1个停止位)
CREAD 接收使能
PARENB 校验位使能
PARODD 使用奇校验而不使用偶校验
HUPCL 最后关闭时挂线(放弃DTR)
CLOCAL 本地连接(不改变端口所有者)
LOBLK 块作业控制输出
CNET_CTSRTS 硬件流控制使能 c_iflag支持的常量名称
INPCK 奇偶校验使能
IGNPAR 忽略奇偶校验错误
PARMRK 奇偶校验错误掩码
ISTRIP 除去奇偶校验位
IXON 启动出口硬件流控
IXOFF 启动入口软件流控
IXANY 允许字符重新启动流控
IGNBRK 忽略中断情况
BRKINT 当发生中断时发送SIGINT信号
INLCR 将NL映射到CR
IGNCR 忽略CR
ICRNL 将CR映射到NL
IUCLC 将高位情况映射到低位情况
IMAXBEL 当输入太长时回复ECHO c_cc 支持的常量名称
VINTR 中断控制,对应键为CTRL+C
VQUIT 退出操作,对应键为CRTL+Z
VERASE 删除操作,对应键为Backspace(BS)
VKILL 删除行,对应键为CTRL+U
VEOF 位于文件结尾,对应键为CTRL+D
VEOL 位于行尾,对应键为Carriage return(CR)
VEOL2 位于第二行尾,对应键为Line feed(LF)
VMIN 指定了最少读取的字符数
VTIME 指定了读取每个字符的等待时间 串口控制函数
Tcgetattr 取属性(termios结构)
Tcsetattr 设置属性(termios结构)
cfgetispeed 得到输入速度
Cfgetospeed 得到输出速度
Cfsetispeed 设置输入速度
Cfsetospeed 设置输出速度
Tcdrain 等待所有输出都被传输
tcflow 挂起传输或接收
tcflush 刷清未决输入和/或输出
Tcsendbreak 送BREAK字符
tcgetpgrp 得到前台进程组ID
tcsetpgrp 设置前台进程组ID

常见参数

获取和设置termios结构

#include <termios.h>
#include <unistd.h> int tcgetattr(int fd, struct termios *termios_p); int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
两个函数的返回值:成功0,出错-1
fd:若fd没有引用中断设备则出错返回-1
optional_actions:指定什么时候新的终端属性起作用。
  TCSANOW 更改立即发生
  TCSADRAIN 发送了所有输出后更改才发生。若更改输出参数则应使用此选项
  TCSAFLUSH 发送了所有输出后更改才发生。更进一步,在更改发生时未读的所有输入数据都被丢弃(冲洗)

例子:

 #include "apue.h"
#include <termios.h> int main(void)
{
struct termios term;
long vdisable; if(isatty(STDIN_FILENO) == )
err_quit("standard input is not a terminal device"); if((vdisable = fpathconf(STDIN_FILENO, _PC_VDISABLE)) < )
err_quit("fpathconf error or _POSIX_VDISABLE not in effect"); if(tcgetattr(STDIN_FILENO, &term) < ) /* fetch tty state */
err_sys("tcgetattr error"); term.c_cc[VINTR] = vdisable; /* disable INTR character */
term.c_cc[VEOF] = ; /* EOF is Control-B */ if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) < )
err_sys("tcsetattr error"); exit();
}

CTRL+B

该程序先用  isatty  函数来测试  STDIN_FILENO  描述符所指向的文件是否是终端设备,如果测试的文件描述符是指向一个终端设备的话则返回1,否则返回0。

然后使用函数  fpathconf  获取系统中的  _PC_VDISABLE  的值,将这个值保存在  c_cc  数组中的相应位置就可以禁止使用这个位置所代表的特殊字符。

接着我们调用  tcgetattr  函数用来获取终端IO的属性,然后设置  c_cc  数组的  VINTR  的位置为  _PC_VDISABLE,表示禁止使用中断符号CTRL+C。而将VEOF的位置的值更改为2,即表示将文件的结束符号修改为CTRL+B,同理如果要修改为CTRL+A,则这个地方的值为1。

设置波特率

#incldue <termios.h>

speed_t cfgetispeed(const struct termios *termios_p);
spee_t cfgetospeed(const struct termios *termios_p);
两个函数的返回值:波特率值 int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
两个函数的返回值:成功0,出错-1
termios_p:指向termios的指针
speed:波特率速度,是下列常量B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400

使用这些函数时,必须认识到输入、输出波特率是存储在设备的termios结构中的。在调用两个cfget函数中的任意一个之前,要先用tcgetattr获得设备的termios结构。

在调用cfset函数中的任意一个后,要做的就是在termios结构中设置波特率,为了更改到设备中,应当调用tcseattr函数。

行控制函数

#include <termios.h>
#include <unistd.h> int tcdrain(int fd);      //等待所有写入fd中的数据输出
int tcflow(int fd, int action);    //挂起fd上的数据传输或接收
int tcflush(int fd, int queue_selector);    //丢弃要写入fd,但尚未传输的数据,或者收到尚未读取的数据
int tcsendbreak(int fd, int duration);    //传送连续0值比特流,持续一段时间,如果终端使用异步串行数据传输的话
4个函数返回值:成功0,出错-1
fd:引用一个终端设备
action:
TCSANOW:不等数据传输完毕就立即改变属性。
TCSADRAIN:等待所有数据传输结束才改变属性。
TCSAFLUSH:清空输入输出缓冲区才改变属性。
queue_selector:
TCIFLUSH:刷新收到的数据但是不读
TCOFLUSH:刷新写入的数据但是不传送
TCIOFLUSH:同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送
duration:如果是0,至少传输0.25秒,不会超过0.5秒。非零,他发送的时间长度由实现定义

大多数控制终端的名字是/dev/tty,POSIX.1提供了一个运行时函数,可用来确定控制终端的名字。

#include <stdio.h>

char *ctermid(char *s);
返回值:成功返回指向控制终端名的指针,出错返回指向空字符串的指针
s:如果非空,则被认为是一个指针,长度至少为L_ctermid字节的数组,进程的控制终端名存储在该数组中。

如果文件描述符引用一个终端设备,则isatty返回真。

ttyname返回的是在该文件描述符上打开的中断设备的路径名

#include <unistd.h>

int isatty(int fd);
返回值:若为终端设备,返回1(真),否则返回0(假)
char *ttyname(int fd);
返回值:指向终端路径名的指针,出错返回NULL
fd:终端关联的描述符

内核为每个终端和伪终端都维护了一个winsize结构:

struct winsize {
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel;
unsgined short ws_ypixel;
};

apue 第18章 终端I/O的更多相关文章

  1. APUE读书笔记-第18章-终端I/O

    18.1 引言 *终端I/O的用途很广泛,包括用于终端.计算机之间的直接连线.调制解调器以及打印机等等,所以终端I/O系统非常复杂 18.2 综述 *终端I/O有两种不同的工作模式: (1)规范模式输 ...

  2. apue第四章学习总结

    apue第四章学习总结 4.1.若以stat函数去替换lstat函数,会发生: 原来的目录路径: $:~/workspace/apue2/include$ ls -l apue.h abc lrwxr ...

  3. linux内核分析第3章&第18章读书笔记

    linux内核分析第3章&第18章读书笔记 第三章 进程管理 进程:处于执行期的程序(目标码存放在某种存储介质上) 包含资源:可执行程序代码,打开的文件,挂起的信号,内核内部数据,处理器状态, ...

  4. 第18章 集合框架(2)-Set接口

    第18章 集合框架(2)-Set接口 Set是Collection子接口,模拟了数学上的集的概念 Set集合存储特点 1.不允许元素重复 2.不会记录元素的先后添加顺序 Set只包含从Collecti ...

  5. Java 第18章 多态

    18 章  --> 多态 继承: extends 抽象类 abstract (限制类的实例化) 抽象方法 public abstract void show(); //抽象方法只有方法的声明,没 ...

  6. LPTHW 笨方法学python 18章

    看完18章以后,发现第一个练习中,使用了*args读取全部的的输入参数作为一个元组,但是在他的练习中只给了两个变量去赋值,当用户不清楚这个函数的定义时,就可能会给出过多的变量进这个函数,那么就会出现如 ...

  7. 《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(1)-读书笔记

    章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...

  8. 《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(2)-读书笔记

    章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...

  9. apue第七章学习总结

    apue第七章学习总结 1.main函数 程序是如何执行有关的c程序的? C程序总是从main函数开始执行.main函数的原型是 int main(int argc,char *argv[]); 其中 ...

随机推荐

  1. MySQL慢SQL语句常见诱因

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11429037.html 1. 无索引.索引失效导致慢查询 如果在一张几千万数据的表中以一个没有索引的列 ...

  2. Tomcat是否关闭 maxEntriesLocalHeap

    EHCache does not allow attribute "maxEntriesLocalHeap". 这个错误是由于这个属性不支持2.5以下版本 故更新ehcache版本 ...

  3. c++11 中的注意事项

    1. C++11标准中让类的析构函数默认也是noexcept(true)的. 但如果显式地为析构函数指定了noexcept,或者类的基类或成员有noexcept(false)的析构函数,析构函数就不会 ...

  4. 工厂方法配置bean

    1:静态工厂方法配置bean 1):对象 package com.spring.helloworld; public class Car { private String name; private ...

  5. UNP学习第七章

    一.套接口选项 函数getsockopt和setsockopt 函数fcntl 函数ioctl 二.getsockopt和setsockopt函数 #include <sys/socket.h& ...

  6. LCD驱动程序架构和分析

    一.LCD驱动程序架构 1.裸机驱动代码分析 ①LCD初始化:控制器初始化,端口初始化,指明帧缓冲 ②LCD图形显示:将图形数据写入帧缓冲 void lcd_init() { lcd_port_ini ...

  7. OC学习篇之---内存管理介绍和使用

    在之前的一片文章我们说了OC中谓词操作:http://blog.csdn.net/jiangwei0910410003/article/details/41923507,从今天开始我们就来看一下OC中 ...

  8. Ubuntu18.04 禁用笔记本电脑键盘

    1.先在命令行工具中输入 xinput list 找到AT Translated Set 2 keyboard,记住后面的ID,如我的ID为21. 输入命令,设置值为0 xinput 然后笔记本键盘就 ...

  9. Chosen 的 optgroup 第一级单击的时候选择二级的全部

    相关环境 及 版本 Chosen (v1.6.2) https://harvesthq.github.io/chosen/ jQuery (v1.8.3) 官网 http://jquery.com/ ...

  10. 政府网站综合防护系统(网防G01)

    政府网站综合防护系统,简称“网防G01”,是首款专门针对政府网站及服务器等关键信息基础资源进行综合防护的产品,由公安部第一研究所和计算机病毒防治技术国家工程实验室(北京)研发. 网防G01的架构 由服 ...