Linux终端输入输出(termios)函数

termios系列函数-tcgetattr, tcsetattr, tcsendbreak, tcdrain, tcflush, tcflow, cfmakeraw, cfgetospeed, cfgetispeed, cfsetispeed, cfsetospeed, cfsetspeed等,用以获取/设置终端设备的属性/控制/速度。
1. 函数声明
函数声明
#include <termios.h>
#include <unistd.h>
/*获取文件描述符fd对应设备状态置入termios_p所指向结构体中*/
int tcgetattr(int fd, struct termios *termios_p);
/*设置文件描述符对应设备状态*/
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
/*向fd发送0比特*/
int tcsendbreak(int fd, int duration);
/*挂起直到所有写入fd的输出全部发送完毕*/
int tcdrain(int fd);
/*丢弃所有准备写入但还未发送给fd的数据或从fd已接收但还还未被读取的数据*/
/*丢弃对象取决于queue_selector*/
int tcflush(int fd, int queue_selector);
/*挂起fd发送操作或接收操作,挂起对象取决于action*/
int tcflow(int fd, int action);
/*设备终端属性*/
void cfmakeraw(struct termios *termios_p);
/*返回termios_p所指向结构体中的输入波特率*/
speed_t cfgetispeed(const struct termios *termios_p);
/*返回termios_p所指向结构体中的输出波特率*/
speed_t cfgetospeed(const struct termios *termios_p);
/*设置termios_p所指向结构体中的输入波特率*/
int cfsetispeed(struct termios *termios_p, speed_t speed);
/*设置termios_p所指向结构体中的输出波特率*/
int cfsetospeed(struct termios *termios_p, speed_t speed);
/*4.4BSD扩展,设置输入输出波特率*/
int cfsetspeed(struct termios *termios_p, speed_t speed); 
glibc功能测试宏定义:
cfsetspeed(), cfmakeraw(): _BSD_SOURCE
2. termios结构体
大多数termios函数都会用到termios结构。termios结构体定义如下:
 
c_iflag标志常量
  • IGNBRK 忽略输入BREAK条件 
  • BRKINT 如果设置了IGNBRK,BREAK将会被忽略;如果仅仅设置了BRKINT,BREAK将会丢弃输入和输出队列中的数据(flush),并且如果终端为前台进程组的控制终端,则BREAK将会产生一个SIGINT信号发送到这个前台进程组。如果IGNBRK和BRKINT均未设置,BREAK将会被当作读入了null字节('\0'),除非设置了PARMRK标志被设置,在这种情况下,BREAK将会被当作读入了\377\0\0序列。 
  • IGNPAR 忽略帧错误和奇偶校验错误 
  • PARMRK 如果未设置IGNPAR标志,在带有奇偶校验错误或帧错误的字符前使用\377\0来标志;如果IGNPAR和PARMRK均未设置,则将奇偶校验错误的字符当作\0 
  • INPCK 允许输入奇偶校验 
  • ISTRIP 剥离第8个bit 
  • INLCR 将输入中的NL转换成CR 
  • IGNCR 忽略输入中的回车 
  • ICRNL 将输入中的CR转换为NL 
  • IUCLC (非POSIX)将输入中的大写字符转换为小写 
  • IXON 允许输出端的XON/XOFF流控 
  • IXANY (XSI)任意击键将会重启已停止的输出(默认情况仅允许使用START字符来重启输出) 
  • IXOFF 允许输入端XON/XOFF流控 
  • IMAXBEL (非POSIX)输入队列满时响铃。Linux未实现此标志位,总是以此标志位被设置的情况动作 
  • IUTF8 (从Linux 2.6.4开始支持,非POSIX)输入为UTF8编码 
c_oflag标志常量定义(POSIX.1):
  • OPOST 允许实现定义的输出处理 
  • OLCUC (非POSIX)将输出中的小写字母映射为大写 
  • ONLCR (XSI)将输出中的NL映射为CR-NL 
  • OCRNL 将输出中的CR映射为NL 
  • ONOCR 不在第零列输出CR 
  • ONLRET 不输出CR 
  • OFILL 发送填充字符实现延迟,而不是使用时间上的延迟 
  • OFDEL (非POSIX)填充字符为ASCII DEL(0177)。如果未设置,填充字符为ASCII NUL('\0')。(Linux中未实现) 
  • NLDLY 新行延迟掩码。值为NL0和NL1。(需要_BSD_SOURCE或_SVID_SOURCE或_XOPEN_SOURCE) 
  • CRDLY 回车(CR)延迟掩码。值为CR0,CR1,CR2,或CR3。(需要_BSD_SOURCE或_SVID_SOURCE或_XOPEN_SOURCE) 
  • TABDLY 水平制表符延迟掩码。值为TAB0,TAB1,TAB2,TAB3(或XTABS)。值TAB3/XTABS表示将制表符扩展为空格(每8列为一个制表符停止位)。(需要_BSD_SOURCE或_SVID_SOURCE或_XOPEN_SOURCE) 
  • BSDLY 回退符延迟掩码。值为BS0或BS1.(从未实现)(需要_BSD_SOURCE或_SVID_SOURCE或_XOPEN_SOURCE) 
  • VTDLY 垂直制表符延迟掩码。值为VT0或VT1。 
  • FFDLY 表单输入延迟掩码。值为FF0或FF1.(需要_BSD_SOURCE或_SVID_SOURCE或_XOPEN_SOURCE) 
c_cflag标志常量:
  • CBAUD (非POSIX)波特速率掩码(4+1比特)。(需要_BSD_SOURCE或_SVID_SOURCE或_XOPEN_SOURCE) 
  • CBAUDEX (非POSIX)附加波特速率掩码(1比特),包含在CBAUD中。(需要_BSD_SOURCE或_SVID_SOURCE或_XOPEN_SOURCE) 
  • CSIZE 字符尺寸掩码。值为CS5,CS6,CS7,或CS8 
  • CSTOPB 设置两个停止位(bits),而不是一位 
  • CREAD 允许接收器 
  • PARENB 允许输出端生产奇偶校验位,输入端进行校验 
  • PARODD 如设置,则输入输出端奇偶校验为奇校验;未设置则为偶校验 
  • HUPCL 上一次操作关闭设备后将调制解调器控制线设为低电平(挂起) 
  • CLOCAL 忽略调制解调器控制线 
  • LOBLK (非POSIX)阻塞非当前shell层输出。(Linux未实现) 
  • CIBAUD (非POSIX)输入速率掩码。 
  • CMSPAR (非POSIX)使用"stick"奇偶校验:如果设置了PARODD,将奇偶检验位总是置为1;如果未设置PARODD,奇偶校验位总是置为0. 
  • CRTSCTS 允许RTS/CTS(硬件)流控。(需要_BSD_SOURCE或_SVID_SOURCE) 
c_lflag标志常量:
  • ISIG 当接收到INTR/QUIT/SUSP/DSUSP字符,生成一个相应的信号 
  • ICANON 允许canonical模式 
  • XCASE (非POSIX,Linux不支持)如果设置了ICANON,终端仅为大写字符模式。输入字符被转换为小写,除非以'\'开始;输出端,大写字符以'\'开始,小写字符被转换为大写 
  • ECHO 回显所输入的字符 
  • ECHOE 如果同时设置了ICANON标志,ERASE字符删除前一个所输入的字符,WERASE删除前一个输入的单词 
  • ECHOK 如果同时设置有ICANON标志,KILL字符删除当前行 
  • ECHONL 如果同时设置有ICANON标志,回显NL字符即使ECHO未设置 
  • ECHOCTL (非POSIX)如果同时设置有ECHO标志,除TAB/NL/START/STOP外的ASCII控制字符将会被回显成'^X',其中X为控制符数值加0x40 
  • ECHOPRT (非POSIX)如果同时设置有ICANON和IECHO,字符以已删除方式打印 
  • ECHOKE (非POSIX)如果设置有ICANON,KILL以删除所在行所有字符方式显示 
  • DEFECHO (非POSIX)仅当有进程读取时回显字符(Linux未实现) 
  • FLUSHO (非POSIX,LINUX不支持)输出被丢弃。 
  • NOFLSH 当生成SIGINT/SIGQUIT/SIGSUSP信号时禁止丢弃(flush)输入输出队列 
  • TOSTOP 当后台进程试图写入自己的控制终端时,发送SIGTTOU信号给进程组 
  • PENDIN (非POSIX,Linux不支持) 
  • IEXTEN 允许实现所定义的输入处理。 
c_cc数组定义了一些特殊控制字符:
  • VINTR 003,ETX,Ctrl-C,0177,DEL,rubout,中断字符。发送SIGINT信号。 
  • VQUIT 034,FS,Ctrl-\,退出字符。发送SIGQUIT信号。 
  • VERASE 0177,DEL,rubout,010,BS,Ctrl-H,#, 删除字符。删除上一个未删除的字符,但不删除前面的EOF或者行开始字符。 
  • VKILL 025,NAK,Ctrl-U,Cgtrl-X,@,Kill字符。删除自上一个EOF或行开始字符之后的所有输入字符。 
  • VEOF 004,EOT,Ctrl-D,文件结尾(End-of-file)。EOF将会让挂起的tty缓冲区内容发送给处于等待中的用户程序,而不用等待行结束标识(End-of-line)。 
  • VMIN 非canonical模式读操作的最少字符数 
  • VEOL (0,NUL)额外的行结束符(End-of-line) 
  • VTIME 非canonical模式读操作超时(单位为1/10秒) 
  • VEOL2 (非POSIX;0,NUL)另一个行结束标识 
  • VSWTCH (非POSIX;Linux不支持;0,NUL)切换字符 
  • VSTART 021,DC1,Ctrl-Q,开始字符。重启被STOP字符停止的输出 
  • VSTOP 023,DC3,Ctrl-S,停止字符。停止输出直到START 
  • VSUSP 032,SUB,Ctrl-Z,挂起字符。发送SIGSTP信号 
  • VDSUSP (非POSIX;Linux不支持)031,EM,Ctrl-Y,延迟挂起字符:当用户程序读取字符时发送SIGTSTP信号 
  • VLNEXT (非POSIX)026,SYN,Ctrl-V,标识下一个字符为字面意思而非可能的特殊控制含义 
  • VWERASE (非POSIX)027,ETC,Ctrl-W,单词删除 
  • VREPRINT (非POSIX)022,DC2,Ctrl-R,再次打印未读取字符 
  • VDISCARD (非POSIX;Linux不支持)017,SI,Ctrl-O,开关切换:开始/停止丢弃挂起的输出 
  • VSTATUS (非POSIX;Linux不支持)024,DC4,Ctrl-T,状态请求 
3. 获取/更改终端设置
tcgetattr(),tcsetattr()分别用于获取/更改终端设置
  • tcgetattr() 获取fd所指定终端的设置并存放入termios结构指针termios_p指向的地址空间;后台进程所获取的终端设置也可能随后被前台进程更改 
  • tcsetattr() 设置指定终端的属性。可选动作项指定终端属性何时更改: 
    • TCSANOW 立即更改 
    • TCSADRAIN 当写入fd的所有输出发送完毕后更改 
    • TCSAFLUSH 所有写入fd的输出发送完毕,并且所有已接收但未读入的输入被丢弃后更改设置 
4. Canonical和non-canonical模式
c_lflag字段中的ICANON标志决定终端是否工作在canonical模式。缺省情况下,终端为canonical模式
canonical模式
  • 输入工作在行模式。收到行定界符(NL,EOL,EOL2;或行首的EOF)后,输入行可供读取。read操作所读取的行内容包含行定界符。 
  • 允许行编辑(ERASE,KILL;如设置了IEXTEN标志,WERASE,REPRINT,LNEXT)。 
non-canonical模式下,无需用户输入行定界符,输入立即可读取。
c_cc[VTIME]和c_cc[VMIN]对read操作的影响: 
 
  • MIN==0;TIME==0:如有数据可用,read立即返回min(请求数量,可用字符数量)个字符;如无数据可用,read返回0 
  •  
  • MIN>0;TIME==0:read阻塞,直到至少有min(请求数量,MIN)个字符可用,read返回两值中较小的一个 
  • MIN==0;TIME>0:TIME指定读取超时(单位为1/10秒)。当调用read时设定定时器。当至少有一个字符可用或超时后,read返回。如果在超时前无可用字符,read返回0 
  • MIN>0;TIME>0:TIME指定读取超时,收到输入的第一个字符后重启定时器。read在读取到MIN和所请求数量两者中较少的字符,或超时后,返回。至少会读取到一个字符。 
5. Raw模式
cfmakeraw()设置终端工作在"raw"模式下:输入以字符方式提供,禁止回显,所有特殊字符被禁止。
raw模式下,终端属性如下:
  1. termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP   
  2.                       | INLCR | IGNCR | ICRNL | IXON);   
  3. termios_p->c_oflag &= ~OPOST;   
  4. termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);   
  5. termios_p->c_cflag &= ~(CSIZE | PARENB);   
  6. termios_p->c_cflag |= CS8;  
6. 线控
控制与终端的连接
  • tcsendbreak 如果终端工作在异步串行数据发送模式,在指定时长内发送0比特流。如果时长为0,发送0比特流至少0.25s,但不多于0.5s。如果终端未工作在异步串行数据发送模式,tcsendbreak立刻返回不作任何操作。 
  • tcdrain() 等待直到所有输出至fd的数据均被发送 
  • tcflush() 丢弃已写入fd但还未发送的数据,或丢弃已接收但还未读取的数据。丢弃对象取决于queue_selector: 
    • TCIFLUSH 丢弃已接收但还未读取的数据 
    • TCOFLUSH 丢弃已写入但还未发送的数据 
    • TCIOFLUSH 丢弃以上两种 
  • tcflow() 挂起fd的发送或接收操作。挂起对象取决于action: 
    • TCOOFF 挂起输出 
    • TCOON 重启挂起的输出 
    • TCIOFF 发送STOP字符,停止终端设备向系统发送数据 
    • TCION 发送START字符,启动设备向系统发送数据 
7. 线速
控制输入/输出波特率
设置波特率为B0会使调制解调器挂起(Hang up)。B38400对应的实际速率可能会受到setserial(8)的影响。 
 
  • cfgetospeed()返回输出波特率 
  • cfsetospeed()设置输出波特率为B0/B50/B75/B110/B134/B150/B200/B300/B600/B1200/B1800/B2400/B4800/B9600/B38400/B57600/B115200/B230400
    *B0用于终止连接 
  • cfgetispeed() 返回输入波特率 
  • cfsetispeed() 设置输入波特率 
  • cfsetspeed() 4.4BSD扩展,同时将输入输入波特率设置为同一值 
8. 返回值
标识函数调用结果
  • cfgetispeed()/cfgetospeed() 返回输入/输出波特率 
  • 对其他函数,返回值为0表示成功;-1表示失败,errno给出错误
    *对于tcsetattr(),只要任一要更改的属性设置成功,则会返回成功。 
9. 例
获取标准输入终端(STDIN)的属性并更改标准输入终端为raw模式(也可以使用更简便的调用-cfmakeraw()完成),接收键盘输入、显示键值,直到接收到Ctrl-b输入。
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
  1. #include <stdio.h>   
  2. #include <unistd.h>   
  3. #include <termios.h>   
  4. #include <errno.h>   
  5. #include <string.h>   
  6. #include <stdlib.h>   
  7.   
  8. #define BUF_LENGTH 255   
  9.   
  10. int main(void)   
  11. {   
  12.     int ret = 0;   
  13.     char buf[BUF_LENGTH]={0};   
  14.     int i = 0;   
  15.   
  16.     struct termios newtmios={0};   
  17.     struct termios oldtmios={0};   
  18.   
  19.     ret = tcgetattr(STDIN_FILENO, &oldtmios);   
  20.     if ( ret )   
  21.     {   
  22.         printf("tcgetattr() error, errno = 0x%X\n", errno);   
  23.         return -1;   
  24.     }   
  25.   
  26.     memcpy(&newtmios, &oldtmios, sizeof(struct termios));   
  27.     newtmios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP   
  28.                 | INLCR | IGNCR | ICRNL | IXON);   
  29.     newtmios.c_oflag &= ~OPOST;   
  30.     newtmios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);   
  31.     newtmios.c_cflag &= ~(CSIZE | PARENB);   
  32.     newtmios.c_cflag |= CS8;   
  33.   
  34.     ret = tcsetattr(STDIN_FILENO, TCSANOW, &newtmios);   
  35.     if ( ret )   
  36.     {   
  37.         printf("tcsetattr() error, errno = 0x%X\n", errno);   
  38.         return -2;   
  39.     }   
  40.   
  41.     printf("Press any key(Ctrl-b to quit) :\n ");   
  42.     tcdrain(STDIN_FILENO);   
  43.     while ( 1 )   
  44.     {   
  45.         ret = read(STDIN_FILENO, buf, BUF_LENGTH);   
  46.         if ( ret )   
  47.         {   
  48.             printf("\rread %d chars, you pressed ", ret);   
  49.             for(i=0; i<ret;i++) printf(" 0x%02X ", buf[i]);   
  50.             printf("\r\n");   
  51.   
  52.             if ( (1==ret) && (0x02 == buf[0]) )   
  53.             {   
  54.                 break;   
  55.             }   
  56.         }   
  57.     }   
  58.   
  59.     ret = tcsetattr(STDIN_FILENO, TCSANOW, &oldtmios);   
  60.     return ret;   
  61. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值