标签:终端io
终端 IO 是一种字符型设备,终端特殊设备文件一般有以下几种:
终端 IO 有两种不同的工作模式:
终端设备是由一般位于内核中的终端驱动程序控制,每个终端设备有一个输入队列和一个输出队列,如下图所示:
大多数 UNIX 系统在一个称为终端行规程的模块中进行规范处理。它位于内核通用读、写函数和实际设备驱动程序之间的模块,如下图所示:
操作终端的结构定义如下:
/* 终端IO */
/* 终端IO的数据结构 */
#include <termios.h>
struct termios
{
tcflag_t c_iflag; /* input flag */
tcflag_t c_oflag; /* output flag */
tcflag_t c_cflag; /* control flag */
tcflag_t c_lflag; /* local flag */
cc_t c_cc[NCCS]; /* control characters */
};
以下先给出终端的操作函数:
/*_______________________________________ * 函数 说明 *_______________________________________ * tcgetattr 获取属性 * tcsetattr 设置属性 *_______________________________________ * cfgetispeed 得到输入速度 * cfgetospeed 得到输出速度 * cfsetispeed 设置输入速度 * cfsetospeed 设置输出速度 *_______________________________________ * tcdrain 等待所有输出都被传输 * tcflow 挂起传输或接收 * tcflush 刷清未决输入和/或输出 * tcsendbreak 送BREAK字符 *_______________________________________ * tcgetpgrp 得到前台进程组ID * tcsetpgrp 设置前台进程组ID * tcgetsid 得到控制TTY的会话首进程的进程组ID *_______________________________________ * */
针对这些终端操作函数进行分类讨论:
可以通过以下两个函数获取和设置终端属性,该属性结构是 termios 结构,有了终端属性方便进一步的操作,其定义如下:
/* * 函数功能:获取和设置终端属性; * 返回值:若成功则返回0,出错则返回-1; * 函数原型: */ #include <termios.h> int tcgetattr(int filedes, struct termios *termptr);/* 获取终端属性 */ int tcsetattr(int filedes, int opt, const struct termios *termptr);/* 设置终端属性 */ /* * 说明: * filed是终端设备描述符; * * opt参数可以指定为以下的值: * TCSANOW 更改立即生效; * TCSADRAIN 发送所有输出后更改才发生,若更改输出参数则应该使用此选项; * TCSAFLUSH 发送所有输出后更改才发生,更进一步,在更改发生时未读的所有输入数据都被删除; */
测试程序:
#include "apue.h"
#include <termios.h>
int main()
{
struct termios term;
//获取termios结构
if(tcgetattr(STDIN_FILENO,&term) < 0)
err_sys("tcgetattr error");
switch(term.c_cflag & CSIZE)
{
case CS5:
printf("5 bits/byte\n");
break;
case CS6:
printf("6 bits/byte\n");
break;
case CS7:
printf("7 bits/byte\n");
break;
case CS8:
printf("8 bits/byte\n");
break;
default:
printf("Unknown bityes/byte\n");
}
term.c_cflag &= ~CSIZE; //字符长度清0
term.c_cflag |= CS5; //设置为8 bites/byte
if(tcsetattr(STDIN_FILENO,TCSANOW,&term) < 0)
err_sys("tcsetattr error");
exit(0);
}
输出结果:
8 bits/byte
/* * 函数功能:获取和设置终端波特率; * 函数原型: */ #include <termios.h> /* 返回值:若成功则返回波特率值 */ speed_t cfgetispeed(const struct termios *termptr);/* 获取输入波特率 */ speed_t cfgetospeed(const struct termios *termptr);/* 获取输出波特率 */ /* 返回值:若成功则返回0,出错则返回-1;*/ int cfsetispeed(struct termios *termptr, speed_t speed);/* 设置输入波特率 */ int cfsetospeed(struct termios *termptr, speed_t speed);/* 设置输出波特率 */
/* * 函数功能:终端设备的行控制; * 返回值:若成功则返回0,若出错则返回-1; * 函数原型: */ #include <termios.h> int tcdrain(int filedes); int tcflow(int filedes, int action); int tcflush(int filedes, int queue); int tcsendbreak(int filedes, int duration); /* * 说明: * action参数取值如下: * TCOOFF 输出被挂起; * TCOON 重新启动以前被挂起的输出; * TCIOFF 系统发送一个STOP字符,将使终端设备暂停发送数据; * TCION 系统发送一个START字符,将使终端设备恢复发送数据; * * queue参数取值如下: * TCIFUSH 刷清输入队列; * TCOFUSH 刷清输出队列; * TCIOFUSH 刷清输入、输出队列; */
下面是一些对控制终端操作的函数,其定义如下:
/* 终端标识 */ /* * 函数功能:确定控制终端的名字; * 返回值:若成功则返回指向控制终端名的指针,出错则返回指向空字符串的指针; * 函数原型: */ #include <stdio.h> char * ctermid(char *ptr); /* * 说明: * ptr非null,且指向长度至少为L_ctermid字节的数组,进程的控制终端名存放在该数组中; * ptr为null,则该函数为数组分配空间,进程的控制终端名也放在该数组中; */ /* * 函数功能:控制终端的操作; * 函数原型: */ #include <unistd.h> int isatty(int filedes); /* 返回值:若为终端设备则返回1(真),否则返回0(假)*/ char *ttyname(int filedes); /* 返回值:指向终端路径名的指针,若出错则返回NULL */下面程序是测试控制终端的信息:
#include "apue.h"
#include <termios.h>
static char ctermid_name[L_ctermid];
char *Mctermid(char *str)
{
if(str == NULL)
str = ctermid_name;
return (strcpy(str,"/dev/tty"));
}
int main()
{
char tername[50];
char *name;
ctermid(tername);
printf("terminate name is: %s\n", tername);
Mctermid(tername);
printf("Mterminate name is: %s\n", tername);
printf("Test isatty...\n");
printf("fd 0 is: %s\n",isatty(0)? "tty" : "not a tty");
printf("fd 1 is: %s\n",isatty(1)? "tty" : "not a tty");
printf("fd 2 is: %s\n",isatty(2)? "tty" : "not a tty");
printf("Test ttyname...\n");
if(isatty(0))
{
name = ttyname(0);
if(name == NULL)
name ="undefined";
}
else
name = "not a tty";
printf("fd 0 :%s\n", name);
if(isatty(1))
{
name = ttyname(1);
if(name == NULL)
name ="undefined";
}
else
name = "not a tty";
printf("fd 1 :%s\n",name);
if(isatty(2))
{
name = ttyname(2);
if(name == NULL)
name ="undefined";
}
else
name = "not a tty";
printf("fd 2 :%s\n",name);
exit(0);
}
输出结果:
./tty < /dev/console 2> /dev/null terminate name is: /dev/tty Mterminate name is: /dev/tty Test isatty... fd 0 is: tty fd 1 is: tty fd 2 is: not a tty Test ttyname... fd 0 :/dev/console fd 1 :/dev/pts/1 fd 2 :not a tty
内核为每个终端和伪终端保存了一个窗口大小结构 winszie,
/* 终端的窗口大小 */
/* 窗口大小的结构体 */
struct winsize
{
unsigned short ws_row; /* row, in characters */
unsigned short ws_col; /* columns, in characters */
unsigned short ws_xpixel; /* horizontal size, pixels (unused) */
unsigned short ws_ypixel; /* vertical size, pixels (unused) */
};
下面程序实现打印当前终端的窗口大小:#include "apue.h"
#include <termios.h>
#include <sys/ioctl.h>
#include <signal.h>
static void pr_winsize(int fd)
{
struct winsize size;
if(ioctl(fd,TIOCGWINSZ,(char *)&size) < 0)
err_sys("ioctl error");
printf("%d rows, %d columns\n", size.ws_row, size.ws_col);
}
static void sig_winch(int signo)
{
printf("SIGWINCH received\n");
pr_winsize(STDIN_FILENO);
}
int main()
{
if(isatty(STDIN_FILENO) == 0)
{
printf("STDIN_FILENO is not terminate device.\n");
exit(1);
}
if(signal(SIGWINCH, sig_winch) == SIG_ERR)
err_sys("signal error");
pr_winsize(STDIN_FILENO);
for( ; ;)
pause();
}
输出结果:
/* 改变终端的窗口大小时会发送信号 SIGWINCH */ 24 rows, 80 columns SIGWINCH received 24 rows, 79 columns ^C
《UNIX高级环境编程》
《unix高级环境编程》终端 I/O——终端 IO 基本概述
标签:终端io
原文地址:http://blog.csdn.net/chenhanzhun/article/details/41378807