终端I/O有两种不一样的工做模式:ios
(1)规范模式:输入以行单位进行处理,每一个读请求也最多返回一行。数组
(2)非规范模式:输入字符不装配成行。异步
终端设备是由一般位于内核中的终端驱动程序控制的。每一个终端设备都有一个输入队列和一个输出队列。ide
终端行规程(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结构fetch
#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 发送了全部输出后更改才发生。更进一步,在更改发生时未读的全部输入数据都被丢弃(冲洗)
例子:ui
1 #include "apue.h" 2 #include <termios.h> 3 4 int main(void) 5 { 6 struct termios term; 7 long vdisable; 8 9 if(isatty(STDIN_FILENO) == 0) 10 err_quit("standard input is not a terminal device"); 11 12 if((vdisable = fpathconf(STDIN_FILENO, _PC_VDISABLE)) < 0) 13 err_quit("fpathconf error or _POSIX_VDISABLE not in effect"); 14 15 if(tcgetattr(STDIN_FILENO, &term) < 0) /* fetch tty state */ 16 err_sys("tcgetattr error"); 17 18 term.c_cc[VINTR] = vdisable; /* disable INTR character */ 19 term.c_cc[VEOF] = 2; /* EOF is Control-B */ 20 21 if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) < 0) 22 err_sys("tcsetattr error"); 23 24 exit(0); 25 }
该程序先用 isatty 函数来测试 STDIN_FILENO 描述符所指向的文件是不是终端设备,若是测试的文件描述符是指向一个终端设备的话则返回1,不然返回0。spa
而后使用函数 fpathconf 获取系统中的 _PC_VDISABLE 的值,将这个值保存在 c_cc 数组中的相应位置就能够禁止使用这个位置所表明的特殊字符。3d
接着咱们调用 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; };