zoukankan      html  css  js  c++  java
  • Unix环境高级编程(十九)终端I/O

      终端I/O应用很广泛,用于终端、计算机之间的直接连线、调制解调器以及打印机等等。终端I/O有两种不同的工作模式:

      (1)规范模式输入处理:终端输入以行为单位进行处理,对于每个读要求,终端驱动程序最多返回一行。(默认模式)

      (2)非规范模式输入处理:输入字符并不组成行。

      终端设备是由一般位于内核的终端驱动程序控制的,每个终端设备有一个输入队列和一个输出队列。如下图:

    可以检测和更改的终端设备特性都包含在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];    控制字符
    }
    终端I/O函数

     

    写个程序,更改特殊字符,禁用中断字符和更改文件结束符。程序如下:

    复制代码
    1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <termios.h>
     4 #include <errno.h>
     5 #include <unistd.h>
     6 
     7 int main()
     8 {
     9     struct termios term;
    10     long   vdisable;
    11     //判断标准输入是否是终端设备
    12     if(isatty(STDIN_FILENO) == 0)
    13     {
    14         printf("Standard input is not a terminal device.
    ");
    15         exit(-1);
    16     }
    17     if((vdisable = fpathconf(STDIN_FILENO,_PC_VDISABLE))<0)
    18     {
    19         perror("fpathconf eeror or _POSIX_VDISABLE not in effect");
    20         exit(-1);
    21     }
    22     //获取termios结构
    23     if(tcgetattr(STDIN_FILENO,&term) < 0)
    24     {
    25         perror("tcgetattr error");
    26         exit(-1);
    27     }
    28 
    29     term.c_cc[VINTR] = vdisable;
    30     term.c_cc[VEOF] = 2;
    31     //设置termios结构
    32     if(tcsetattr(STDIN_FILENO,TCSAFLUSH,&term) < 0)
    33     {
    34         perror("tcsetattr error");
    35         exit(-1);
    36     }
    37     return 0;
    38 }
    复制代码
     

    获取和设置终端属性函数:

    int tcgetattr(int fd, struct termios *termios_p);
    int tcsetattr(int fd, int optional_actions,const struct termios *termios_p);

    调用以上函数屏蔽标志取或设置一个值,程序如下:

    复制代码
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <termios.h>
     4 #include <errno.h>
     5 #include <unistd.h>
     6 
     7 int main()
     8 {
     9     struct termios term;
    10     //获取termios结构
    11     if(tcgetattr(STDIN_FILENO,&term) < 0)
    12     {
    13         perror("tcgetattr error");
    14         exit(-1);
    15     }
    16     switch(term.c_cflag & CSIZE)
    17     {
    18     case CS5:
    19         printf("5 bits/byte
    ");
    20         break;
    21     case CS6:
    22         printf("6 bits/byte
    ");
    23         break;
    24     case CS7:
    25         printf("7 bits/byte
    ");
    26         break;
    27     case CS8:
    28         printf("8 bits/byte
    ");
    29         break;
    30     default:
    31         printf("Unknown bityes/byte
    ");
    32     }
    33     term.c_cflag &= ~CSIZE;   //字符长度清0
    34     term.c_cflag |= CS5;          //设置为8 bites/byte
    35     if(tcsetattr(STDIN_FILENO,TCSANOW,&term) < 0)
    36     {
    37         perror("tcsetattr error");
    38         exit(-1);
    39     }
    40     return 0;
    41 }
    复制代码
     

    stty命令:在终端中输入stty -a命令显示终端的所有选项,执行命令结果如下:

    终端标识:在大多数UNIXi系统中,控制终端的名字是/dev/tty。

    char *ctermid(char *s);  //获取终端控制名字

    int isatty(int fd); //判断fd是否为终端设备

    char *ttyname(int fd);  // 获取终端设备的路径名

    写个程序输出控制终端的标识符信息,程序如下:

    复制代码
    1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <termios.h>
     4 #include <unistd.h>
     5 #include <string.h>
     6 static char ctermid_name[L_ctermid];
     7 char* my_ctermid(char *str)
     8 {
     9     if(str == NULL)
    10         str = ctermid_name;
    11     return (strcpy(str,"/dev/tty"));
    12 }
    13 int main()
    14 {
    15     char tername[50];
    16     char *name;
    17     ctermid(tername);
    18     printf("terminate name is: %s
    ",tername);
    19     my_ctermid(tername);
    20     printf("my terminate name is: %s
    ",tername);
    21     printf("Test isatty() function.
    ");
    22     printf("fd 0 is: %s
    ",isatty(0)? "tty" : "not a tty");
    23     printf("fd 1 is: %s
    ",isatty(1)? "tty" : "not a tty");
    24     printf("fd 2 is: %s
    ",isatty(2)? "tty" : "not a tty");
    25     printf("Test ttyname() function.
    ");
    26     if(isatty(0))
    27     {
    28         name = ttyname(0);
    29         if(name == NULL)
    30             name ="undefined";
    31     }
    32     else
    33         name = "not a tty";
    34     printf("fd 0 :%s
    ",name);
    35     if(isatty(1))
    36     {
    37         name = ttyname(1);
    38         if(name == NULL)
    39             name ="undefined";
    40     }
    41     else
    42         name = "not a tty";
    43     printf("fd 1 :%s
    ",name);
    44     if(isatty(2))
    45     {
    46         name = ttyname(2);
    47         if(name == NULL)
    48             name ="undefined";
    49     }
    50     else
    51         name = "not a tty";
    52     printf("fd 2 :%s
    ",name);
    53     exit(0);
    54 }
    复制代码
     

    程序执行结果如下:

    终端的窗口大小:内核为每个终端和伪终端保存了一个窗口大小结构winszie,用ioctl函数的TIOCGWINSZ命令可以获取此结构的当前值。

    struct winsize {

      unsigned short ws_row;

      unsigned short ws_col;

      unsigned short ws_xpixel; /* unused */

      unsigned short ws_ypixel; /* unused */

    };

    写个程序打印终端窗口大小,程序如下:

    复制代码
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <termios.h>
     4 #include <unistd.h>
     5 #include <string.h>
     6 #include <sys/ioctl.h>
     7 #include <signal.h>
     8 #include <errno.h>
     9 
    10 static void pr_winsize(int fd)
    11 {
    12     struct  winsize size;
    13     if(ioctl(fd,TIOCGWINSZ,(char *)&size) < 0)
    14     {
    15         perror("ioctl() error");
    16         exit(-1);
    17     }
    18     printf("%d rows,%d columns
    ",size.ws_row,size.ws_col);
    19 }
    20 static void sig_winch(int signo)
    21 {
    22     printf("SIGWINCH received
    ");
    23     pr_winsize(STDIN_FILENO);
    24 }
    25 int main()
    26 {
    27     if(isatty(STDIN_FILENO) == 0)
    28     {
    29         printf("STDIN_FILENO is not terminate device.
    ");
    30         exit(1);
    31     }
    32     if(signal(SIGWINCH,sig_winch) == SIG_ERR)
    33     {
    34         perror("signal() error");
    35         exit(-1);
    36     }
    37     pr_winsize(STDIN_FILENO);
    38     for( ; ;)
    39      pause();
    40 }
    复制代码

    程序执行结果如下:

    总结:本章介绍了终端,涉及到很多系统底层的知识,很多参数。看的时候只是了解了一些基本的终端操作,还要很多地方不懂,关键是不知道终端用在什么地方,以后用到了需要回头好好学习一下。

  • 相关阅读:
    ACM常用算法及练习(2)
    ACM常用算法及练习(1)
    ACM进阶计划
    《算法艺术与信息学竞赛》题目-提交方式对照表
    ACM之Java速成(4)
    ACM之Java速成(3)
    ACM之Java速成(2)
    ACM之Java速成(1)
    uva 11520
    uva 10755
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8466200.html
Copyright © 2011-2022 走看看