Unix环境编程-终端
1.什么是Linux的终端I/O,它分为几种类型。
终端是一种字符型设备,有多种类型,通常使用tty来简称各种类型的终端设备。终端特殊设备文件一般有以下几种: 串行端口终端(/dev/ttySn) ,伪终端(/dev/pty/),控制终端(/dev/tty) ,控制台终端(/dev/ttyn, /dev/console).
1. 串行端口终端(Serial Port Terminal)是使用计算机串行端口连接的终端设备。计算机把每个串行端口都看作是一个字符设备。串行端口所对应的设备名称是/dev/tts/0(或/dev/ttyS0)、/dev/tts/1(或/dev/ttyS1)等,设备号分别是(4,0)、(4,1)等,分别对应于DOS系统下的COM1、COM2等。
2. 伪终端(Pseudo Terminal)是成对的逻辑终端设备,例如/dev/ptyp3和/dev/ttyp3(在设备文件系统中分别是/dev/pty/m3和/dev/pty/s3),它们与实际物理设备并不直接相关。对于ttyp3(s3),任何设计成使用一个串行端口设备的程序都可以使用该逻辑设备。但对于使用ptyp3的程序,则需要专门设计来使用ptyp3(m3)逻辑设备。 如果使用telnet远程登录,则telnet会开始连接到设备ptyp2(m2)上(一个伪终端端口上)。此时一个getty程序就应该运行在对应的ttyp2(s2)端口上。当telnet从远端获取了一个字符时,该字符就会通过m2、s2传递给getty程序,而getty程序就会通过s2、m2和telnet程序往网络上返回”login:”字符串信息。登录程序与telnet程序就通过“伪终端”进行通信,通过使用适当的软件,就可以把两个甚至多个伪终端设备连接到同一个物理串行端口上。因为只存在16个ttyp(ttyp0—ttypf)的设备文件,就使用了象q、r、s等字符来代替p。例如,ttys8和ptys8就是一个伪终端设备对。目录/dev/pts是一个类型为devpts的文件系统,并且可以在被加载文件系统列表中看到。虽然/dev/pts象是设备文件系统中的一项,但它其实是一种不同的文件系统。
3. 如果当前进程有控制终端(Controlling Terminal)的话,那么/dev/tty就是当前进程的控制终端的设备特殊文件。可以使用命令”ps –ax”来查看进程与哪个控制终端相连使用命令”tty”可以查看它具体对应哪个实际终端设备。/dev/tty有些类似于到实际所使用终端设备的一个联接。
4. Linux系统中,计算机显示器通常被称为控制台终端(Console),它仿真了类型为Linux的一种终端(TERM=Linux),并且有一些设备特殊文件与之相关联:tty0、tty1、tty2等。当你在控制台上登录时,使用的是tty1。使用Alt+[F1—F6]组合键时,我们就可以切换到tty2、tty3等上面去。tty1 –tty6等称为虚拟终端,而tty0则是当前所使用虚拟终端的一个别名,系统所产生的信息会发送到该终端上。只有系统或超级用户root可以向/dev/tty0进行写操作 .
2.终端I/O有两种不同的工作方式:
(1) 规范方式输入处理。在这种方式中,终端输入以行为单位进行处理。对于每个读要求驱动程序最多返回一行。
(2) 非规范放式输入处理。输入字符不以行为单位进行装配。
3.终端标志
在Unix/Linux终端设备特性都包含在termios结构中。该结构在头文件<termios.h>中定义。
struct termios{
tcflag_t c_iflag; /*输入标志*/
tcflag_t c_oflag;/*输出标志*/
tcflag_t c_cflag;/*控制标志*/
tcfag_t c_lflag;/*本地标志*/
cc_t c_cc[NCCS];/*控制字符*/
};
下面对他们分别进行介绍。
|
字段 |
标志 |
说明 |
|
c_iflag |
BRKINT |
接到BREAK时产生SIGINT |
|
|
ICRNL |
将输入的CR转换为NL |
|
|
IGNBRK |
忽略BREAK条件 |
|
|
IGNCR |
忽略CR |
|
|
IGNPAR |
忽略奇偶错字符 |
|
|
IMAXBEL |
在输入队列空时振铃 |
|
|
INLCR |
将输入的NL转换为CR |
|
|
INPCK |
打开输入奇偶效验 |
|
|
ISTRIP |
剥除输入字符的第8位 |
|
|
IUCLC |
将输入的大写字符转换成小写字符 |
|
|
IXANY |
使任一字符都重起动动输出 |
|
|
IXOFF |
使起动/停止输入控制流起作用 |
|
|
IXON |
使起动/停止输出控制流起作用 |
|
|
PARMRK |
标记奇偶错 |
|
| ||
|
c_oflag |
BSDLY |
退格延迟屏蔽 |
|
|
CRDLY |
CR延迟屏蔽 |
|
|
FFDLY |
换页延迟屏蔽 |
|
|
NLDLY |
NL延迟屏蔽 |
|
|
OCRNL |
将输出的CR转换为NL |
|
|
OFDEL |
填充符为DEL,否则为NUL |
|
|
OFILL |
对于延迟使用填充符 |
|
|
OLCUC |
将输出的小写字符转换为大写字符 |
|
|
ONLCR |
将NL转换为CR-NL |
|
|
ONLRET |
NL执行CR功能 |
|
|
ONOCR |
在0列不输出CR |
|
|
ONOEOT |
在输出中删除EOT字符 |
|
|
OPOST |
执行输出处理 |
|
|
OXTABS |
将制表符扩充为表格 |
|
|
TABDLY |
水平制表符延迟屏蔽 |
|
|
VTDLY |
垂直制表延迟屏蔽 |
|
字段 |
标志 |
说明 |
|
c_cflag |
CCTS_OFLOW |
输出的CTS流控制 |
|
|
CIGNORE |
忽略控制标志 |
|
|
CLOAL |
忽略调制解调器状态行 |
|
|
CREAD |
启用接收装置 |
|
|
CRTS_IFLOW |
输入的RTS流控制 |
|
|
CSIZE |
字符大小屏蔽 |
|
|
CSTOPB |
送两个停止位,否则为1位 |
|
|
HUPCL |
最后关闭时断开 |
|
|
MDMBUF |
经载波的控制输出 |
|
|
PARENB |
进行奇偶校 |
|
|
PARODD |
奇校,否则为偶校 |
|
| ||
|
c_lflag |
ALTWERASE |
使用替换WERASW算法 |
|
|
ECHO |
进行回送 |
|
|
ECHOCTL |
回送控制字符为^(char) |
|
|
ECHOE |
可见符擦除符 |
|
|
ECHOK |
回送kill符 |
|
|
ECHOKE |
kill的可见擦除 |
|
|
ECHONL |
回送NL |
|
|
ECHOPRT |
硬拷贝的可见擦除方式 |
|
|
FLUSHO |
刷清输出 |
|
|
ICANON |
规范输出 |
|
|
IEXTEN |
使扩充的输入字符处理起作用 |
|
|
ISIG |
使终端产生的信号起作用 |
|
|
NOFLSH |
在中断或退出键后不刷清 |
|
|
NOKERNINFO |
STATUS不使内核输出 |
|
|
PENDIN |
重新打印 |
|
|
TOSTOP |
对于后台输出发送SIGTTOU |
|
|
XCASH |
规范大/小写表示 |
4.终端选择标志
所有列出的选择标志都用一或多位表示,而屏蔽标志则定义多位。屏蔽标志有一个定义名,每个值也有一个名字。例如,为了设置字符长度,首先用字符长度屏蔽标志CSIZE将表示字符长度的位清0,然后设置下列值之一:CS5、CS6、CS7、CS8。具体语法看程序11_1.c
5.特殊字符

六.终端I/O函数
tcgetattr 取属性(termios结构)
tcsetattr 设置属性(termios结构)
cfgetispeed 得到输入速度
cfgetospeed 得到输出速度
cfsetispeed 设置输入速度
cfsetospeed 设置输出速度
tcdrain 等待所有输出都被传输
tcflow 挂起传输或接收
tcflush 刷清未决输入和输出
tcsendbread 送BREAK字符
tcgetpgrp 得到前台进程id
tcsetpgrp 设置前台进程id
1.
|
名称:: |
tcgetattr/tcsetattr |
|
功能: |
获得和设置终端属性 |
|
头文件: |
#include <termios.h> |
|
函数原形: |
int tcgetattr(int filedes,struct termios *termptr); int tcsetattr(int filedes,int opt,const struct termios *termptr); |
|
参数: |
filedes 终端I/O所对应的文件的文件描述符 termptr 终端属性 opt 作用时间 |
|
返回值: |
若成功返回0,若出错则返回-1 |
使用这两个函数可以获得或设置termios。这样也就可以检测和修改各种终端选择标志和特殊字符,以使终端按我们所希望的方式进行操作。
这两个函数都有一个指向termios结构的指针作为其参数,它们返回当前终端的属性,或者设置该终端的属性。因为这两函数只对终端进行操作,所以若filedes并不引用一个终端设备则出错返回,errno设置为ENOTTY.
tcsetattr的参数opt使我们可以指定在什么时候新的终端属性才起作用,opt可以指定下列属性中的一个。
TCSANOW 更改立即发生
TCSADRAIN 发送了所有输出后更改才发生
TCSAFLUSH 发送了所有输出后更改才发生,更进一步,在更改发生时未读的所有输入数据都被清空。
tcsetattr函数的返回值易于产生混淆。如果它执行了任意一种所要求的动作,即使未能执行所有要求的动作,它也返回0(表示成功)。如果该函数返回0,则我们有责任检查该函数是否执行了所有要求的动作。这就意味着,在调用tcsetattr设置所希望的属性后,需调用tcgetattr,然后将实际终端属性与所希望的属性相比较,以检测两者是否有区别。
|
/*11_1.c*/ #include <stdio.h> #include <stdlib.h> #include <termios.h> #inlcude <unistd.h> int main() { struct termios term; /*定义终端属性*/ int size; if(tcgetattr(STDIN_FILENO,&term)<0) /* STDIN_FILENO 就对应于标准输入. 实际上是文件描述符1 */ printf(“tcgerattr error”); size=term.c_cflag&CSIZE; /*字符大小*/ if(size==CS5) printf(“5 bits/byte\n”); else if(size==CS6) printf(“6 bits/byte\n”); else if(size==CS7) printf(“7 bits/byte\n”); else if(size==CS8) printf(“8 bits/byte\n”); else printf(“unknown bits/byte\n”); term.c_cflag &=~CSIZE; /*把字符长度位清0*/ term.c_cflag | =CS6; /*设置6bits/byte的长度位*/ if(tcsetattr(STDIN_FILENO,TCSANOW,&term)<0) printf(“tcsetattr error\n”); exit(0); } |
程序运行后在屏幕上输出:8 bits/byte(你的系统有可能不是这个数),当程序再次运行时会打印 8 bits/byte。这就是我们用屏蔽标志设置的一个值。

浙公网安备 33010602011771号