zoukankan      html  css  js  c++  java
  • apue 第18章 终端I/O

    终端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 发送了所有输出后更改才发生。更进一步,在更改发生时未读的所有输入数据都被丢弃(冲洗)

     例子:

     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 }
    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;
    };
    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    阿里巴巴2018秋招面经之前端岗(1~5面)
    面试分享:2018阿里巴巴前端面试总结(题目+答案 30题)
    2018年各大互联网前端面试题三(阿里)
    阿里巴巴2016前端工程师面试题
    2016 阿里校招笔试前端题目,你还记得吗?
    2018阿里前端校招分享(笔试篇)
    2017 阿里校招前端笔试题小结
    阿里2018校招编程题
    ko.js学习一
    简单的3d变换
  • 原文地址:https://www.cnblogs.com/ch122633/p/8093828.html
Copyright © 2011-2022 走看看