终端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.\n");
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\n");
20 break;
21 case CS6:
22 printf("6 bits/byte\n");
23 break;
24 case CS7:
25 printf("7 bits/byte\n");
26 break;
27 case CS8:
28 printf("8 bits/byte\n");
29 break;
30 default:
31 printf("Unknown bityes/byte\n");
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\n",tername);
19 my_ctermid(tername);
20 printf("my terminate name is: %s\n",tername);
21 printf("Test isatty() function.\n");
22 printf("fd 0 is: %s\n",isatty(0)? "tty" : "not a tty");
23 printf("fd 1 is: %s\n",isatty(1)? "tty" : "not a tty");
24 printf("fd 2 is: %s\n",isatty(2)? "tty" : "not a tty");
25 printf("Test ttyname() function.\n");
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\n",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\n",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\n",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\n",size.ws_row,size.ws_col);
19 }
20 static void sig_winch(int signo)
21 {
22 printf("SIGWINCH received\n");
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.\n");
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 }

程序执行结果如下:

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

Unix环境高级编程(十九)终端I/O的更多相关文章

  1. Unix环境高级编程(十五)高级I/O

    1.非阻塞I/O 对低速设备的I/O操作可能会使进程永久阻塞,这类系统调用主要有如下情况:(1)如果数据并不存在,则读文件可能会使调用者永远阻塞(例如读管道.终端设备和网络设备).(2)如果数据不能立 ...

  2. Unix环境高级编程(十二)线程控制

    本章介绍了一个进程中多个线程之间如何保持数据的似有性及进程的系统调用如何与线程进行交互. 1.线程限制: Single Unix定义了一线线程操作的限制,和其他的限制一样,可以通过sysconf来查询 ...

  3. Unix环境高级编程(十八)高级进程间通信

    本章主要介绍了基于STREAM的管道和UNIX域套接字,这些IPC可以在进程间传送打开文件描述符.服务进程可以使用它们的打开文件描述符与指定的名字相关联,客户进程可以使用这些名字与服务器进程通信. 1 ...

  4. Unix环境高级编程(十四)守护进程实现时间服务器

    守护进程是在后台运行不受终端控制的进程(如输入.输出等),一般的网络服务都是以守护进程的方式运行.守护进程脱离终端的主要原因有两点:(1)用来启动守护进程的终端在启动守护进程之后,需要执行其他任务.( ...

  5. Unix环境高级编程(十)信号续

    1.signal函数 Unix系统的信号机制最简单的接口是signal函数,函数原型如下: #include <signal.h> typedef void (*sighandler_t) ...

  6. Unix环境高级编程(十六)进程间通信

    进程间通信(IPC)是指能在两个进程间进行数据交换的机制.现代OS都对进程有保护机制,因此两个进程不能直接交换数据,必须通过一定机制来完成. IPC的机制的作用: (1)一个软件也能更容易跟第三方软件 ...

  7. (九) 一起学 Unix 环境高级编程 (APUE) 之 线程

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  8. (十) 一起学 Unix 环境高级编程 (APUE) 之 线程控制

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  9. (十二) 一起学 Unix 环境高级编程 (APUE) 之 进程间通信(IPC)

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

随机推荐

  1. JS操作JSON常用方法

    一.JSON字符串的替换 工作经常遇到这样的字符串,如下: 需要经过替换后,才能从字符串转化成JSON对象.这里我们需要用JS实现replaceAll的功能, 将所有的 ' \\" ' 替换 ...

  2. JavaScript事件代理和事件委托

    一.概述: 那什么叫事件委托呢?它还有一个名字叫事件代理,JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件.那这是什么意思呢?网上的 ...

  3. linux CentOS7 安装scala

    1.打开terminal ,进入当前用户路径: cd /home/sks 2.下载Scala2.11 wget https://downloads.lightbend.com/scala/2.11.8 ...

  4. 《TCP/IP具体解释卷2:实现》笔记--接口层

    接口层包含在本地网上发送和接收分组的硬件与软件. 我们用设备驱动程序来表示与硬件及网络接口通信的软件,网络接口是指在一个特定网络上硬件与设备驱动器之间的接口. Net/3接口层试图在网络协议和连接到一 ...

  5. IE11与Cognos怪谈

    想必大家都知道高版本的IE运行Cognos相关组件的时候要设置兼容性,安全级别相对调低等设置.但是升级了win10系统后,默认的IE版本是IE11的,装了Cognos10.2.1之后,进行了一个常规的 ...

  6. kettle根据参数动态派生列

    抽取数据的时候没有日期字段,需要根据抽取日期自动生成月份,如下图结构 表输入_参数部分,接收来自其他系统传过来的参数(JAVA程序或者页面),具体设置如图 在查询数据时候派生列 运行模型的时候,给参数 ...

  7. A5-1和DES两个加密算法的学习

    A5-1加密算法 1.基本原理 A5-1加密算法是一种流password,通过密钥流对明文进行加密.然后用密钥流进行对密文的解密操作. 这样的算法主要用于GSM加密.也就是我们平时打电话的时候.通信数 ...

  8. iOS 怎样更新APP

    app更新的流程思想 得到当前版本currentVersion,将currentVersion与近期的版本latestVersion进行比較,若当前currentVersion较小.进行更新操作. 获 ...

  9. 配置Tomcat和JDK

    第一步:下载jdk和tomcat 第二步:安装和配置你的j2sdk和tomcat:执行j2sdk和tomcat的安装程序,然后按默认设置进行安装即可. 1.安装j2sdk以后,需要配置一下环境变量,在 ...

  10. Hibernate(四)结构-基础语义和事务

    一.基础语义 核心: Configuration SessionFactory Session 二.Configuration Configuration类负责管理Hibernate的配置信息,Hib ...