前言:本篇將對終端IO的一系列常用屬性以及函數(shù)進行解讀,,這也是為最后一篇教程進行鋪墊,,希望您仔細閱讀。
什么是終端終端是一種字符型設(shè)備,,它分為一下四種:
終端I/O工作模式終端I/O有兩種工作模式:
終端設(shè)備是由一般位于內(nèi)核中的終端驅(qū)動程序控制,,每個終端設(shè)備有一個輸入隊列和一個輸出隊列。 大多數(shù) UNIX 系統(tǒng)在一個稱為終端行規(guī)程的模塊中進行規(guī)范處理,。它位于內(nèi)核通用讀,、寫函數(shù)和實際設(shè)備驅(qū)動程序之間的模塊。 終端結(jié)構(gòu)體我們可以檢測和更改的終端特性設(shè)備文件都包含在下面這個結(jié)構(gòu)中: #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 */ }; 說明:
- 關(guān)于特殊字符有幾點要說明:
終端操作
#include <termios.h> int tcgetattr(int filedes, struct termios *termptr);/* 獲取終端屬性 */ int tcsetattr(int filedes, int opt, const struct termios *termptr); /* 設(shè)置終端屬性 */ /* *說明: *返回值:若成功則返回0,,出錯則返回-1,。 *fileds是終端設(shè)備描述符,若沒有引用一個終端設(shè)備則出錯返回-1,,errno設(shè)置為ENOTTY,。 *opt參數(shù)可以指定為以下的值: *TCSANOW :更改立即生效。 *TCSADRAIN:發(fā)送所有輸出后更改才發(fā)生,,若更改輸出參數(shù)則應(yīng)該使用此選項,。 *TCSAFLUSH:發(fā)送所有輸出后更改才發(fā)生,更進一步,,在更改發(fā)生時未讀的所有輸入數(shù)據(jù)都被刪除。 */
/************************************************************************* > File Name: example1.c > Author: AnSwEr > Mail: [email protected] > Created Time: 2015年08月31日 星期一 16時25分24秒 ************************************************************************/ /* * tcgetattr和tcsetattr演示 */ #include<stdio.h> #include<termios.h> #include<stdlib.h> #include<unistd.h> int main(void) { struct termios t; /*先獲取終端屬性*/ if(tcgetattr(STDIN_FILENO,&t) < 0) { perror("tcgetattr failed!"); exit(EXIT_FAILURE); } /*與字符屏蔽標志進行與操作,,得到當前的字符長度*/ switch(t.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("unkown bits/byte\n"); } t.c_cflag &= ~CSIZE; //clear out the c_cflag t.c_cflag |= CS8; //set 8bits/byte /*設(shè)置終端屬性*/ if(tcsetattr(STDIN_FILENO,TCSANOW,&t) < 0) { perror("tcsetattr failed!"); exit(EXIT_FAILURE); } /*獲取新的終端屬性*/ if(tcgetattr(STDIN_FILENO,&t) < 0) { perror("tcgetattr failed!"); exit(EXIT_FAILURE); } /*檢測是否設(shè)置成功*/ if((t.c_cflag & CSIZE) == CS8) printf("set successfully!\n"); else printf("set failed!\n"); exit(EXIT_SUCCESS); } 運行結(jié)果:
/*查看當前終端設(shè)置*/ stty -a //顯示終端所有選項,,前面有連字符的說明禁用。 /*查看名為ttya的終端設(shè)置,,*/ stty -a < /dev/ttya
#include <termios.h> speed_t cfgetispeed(const struct termios *termptr);/* 獲取輸入波特率 */ speed_t cfgetospeed(const struct termios *termptr);/* 獲取輸出波特率 */ /* 返回值:若成功則返回波特率值 */ int cfsetispeed(struct termios *termptr, speed_t speed);/* 設(shè)置輸入波特率 */ int cfsetospeed(struct termios *termptr, speed_t speed);/* 設(shè)置輸出波特率 */ /* 返回值:若成功則返回0,,出錯則返回-1;*/ 說明:當speed為B0時,,表示掛斷,,調(diào)制解調(diào)器的控制線不再起作用。波特率函數(shù)的演示將在下一篇中進行,。
#include <termios.h> int tcdrain(int filedes); //等待所有輸出都被發(fā)送 int tcflow(int filedes, int action);//對輸入和輸出控制流進行控制 /* * 參數(shù): * action參數(shù)取值如下: * TCOOFF 輸出被掛起,; * TCOON 重新啟動以前被掛起的輸出; * TCIOFF 系統(tǒng)發(fā)送一個STOP字符,,將使終端設(shè)備暫停發(fā)送數(shù)據(jù),; * TCION 系統(tǒng)發(fā)送一個START字符,將使終端設(shè)備恢復(fù)發(fā)送數(shù)據(jù),; */ int tcflush(int filedes, int queue); //刷新輸入或輸出緩沖區(qū) /* * queue參數(shù)取值如下: * TCIFUSH 刷清輸入隊列,; * TCOFUSH 刷清輸出隊列,; * TCIOFUSH 刷清輸入、輸出隊列,; */ int tcsendbreak(int filedes, int duration); //在一個指定的時間區(qū)內(nèi)發(fā)送連續(xù)的0位流,。 /* * 若duration為0,則發(fā)送延續(xù)0.25至0.5s 之間,,若非0,,則依賴于實現(xiàn)。 */ /*返回值:若成功則返回0,,若出錯則返回-1*/ 具體應(yīng)用見第三篇,。
終端標識
#include <stdio.h> char * ctermid(char *ptr);//確定控制終端的名字 /* * 說明: * 返回值:若成功則返回指向控制終端名的指針,,出錯則返回指向空字符串的指針,; * ptr非null,且指向長度至少為L_ctermid字節(jié)的數(shù)組,,進程的控制終端名存放在該數(shù)組中,; *大多數(shù)系統(tǒng)中,控制終端名字是/dev/tty */ #include <unistd.h> int isatty(int filedes); //判斷文件描述符是否引用一個終端 /* 返回值:若為終端設(shè)備則返回1(真),,否則返回0(假)*/ char *ttyname(int filedes); //獲得在文件描述符上打開的終端設(shè)備的路徑名 /* 返回值:指向終端路徑名的指針,,若出錯則返回NULL */
/************************************************************************* > File Name: example2.c > Author: AnSwEr > Mail: [email protected] > Created Time: 2015年08月31日 星期一 18時48分47秒 ************************************************************************/ /* *isatty 示例 */ #include<stdio.h> #include<unistd.h> int main(void) { printf("fd 0:%s\n",isatty(0)?"tty":"not a tty"); printf("fd 1:%s\n",isatty(1)?"tty":"not a tty"); printf("fd 2:%s\n",isatty(2)?"tty":"not a tty"); return 0; } 運行結(jié)果:
/************************************************************************* > File Name: example3.c > Author: AnSwEr > Mail: [email protected] > Created Time: 2015年08月31日 星期一 18時54分09秒 ************************************************************************/ /* *ttyname函數(shù)示例 */ #include<stdio.h> #include<unistd.h> int main(void) { char *name; if(isatty(STDIN_FILENO)) { name = ttyname(STDIN_FILENO); if(name == NULL) name = "undefined"; } else name = "not a tty"; printf("fd 0:%s\n",name); if(isatty(STDOUT_FILENO)) { name = ttyname(STDOUT_FILENO); if(name == NULL) name = "undefined"; } else name = "not a tty"; printf("fd 1:%s\n",name); if(isatty(STDERR_FILENO)) { name = ttyname(STDERR_FILENO); if(name == NULL) name = "undefined"; } else name = "not a tty"; printf("fd 2:%s\n",name); return 0; } 運行結(jié)果: 規(guī)范模式規(guī)范模式(我們使用的linux系統(tǒng)中的終端):發(fā)一個讀請求,輸入一行后,,終端程序即返回,。下列幾個條件引起讀返回:
非規(guī)范模式非規(guī)范模式是指關(guān)閉termios結(jié)構(gòu)中的c_lflag域的ICANON標志位,。在非規(guī)范模式下,輸入數(shù)據(jù)不組成一行,,下面的一些特殊字符也不進行處 理:ERASSE,, KILL, EOF,,NL,, EOL, EOL2, CR,, REPRINT ,,STATUS 和 WERASE。 利用串口收發(fā)數(shù)據(jù)時一般使用非規(guī)范模式,。
1. MIN >0, TIME>0 TIME從接收到的第一個字節(jié)開始計數(shù),。如果在超時前,接收到MIN個字節(jié),,那么返回MIN個字節(jié),。如果在接收到MIN個字節(jié)前,發(fā)生了時間超時,,則至少有一個字節(jié)返回,,因為計時器是從接收到第一個字節(jié)開始計數(shù)的。 2. MIN >0, TIME == 0 在這種情況下,,直到讀到的字節(jié)數(shù)達到MIN個時才返回,??赡茉斐蓃ead無限阻塞,。 3. MIN==0, TIME >0 TIME的值從調(diào)用read開始計算,如果收到一個字節(jié)或時間超時時返回,。若超時,,read返回0。 4. MIN==0, TIME==0 如果一些數(shù)據(jù)是有效的,,則 read返回這些數(shù)據(jù),。如果沒有數(shù)據(jù)有效,則立即返回0。
/************************************************************************* > File Name: raw_mode.c > Author: AnSwEr > Mail: [email protected] > Created Time: 2015年09月02日 星期三 22時41分14秒 ************************************************************************/ #include<stdio.h> #include<termios.h> #include<stdlib.h> #include<unistd.h> static int RawMode(int fd) { struct termios raw,old; if (!isatty(STDIN_FILENO)) { fprintf(stderr,"not a tty!\n"); exit(EXIT_FAILURE); } if (tcgetattr(fd,&old) == -1) { perror("tcgetattr failed"); exit(EXIT_FAILURE); } raw = old; /* modify the original mode */ /* input modes: no break, no CR to NL, no parity check, no strip char, * no start/stop output control. */ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); /* output modes - disable post processing */ raw.c_oflag &= ~(OPOST); /* control modes - set 8 bit chars */ raw.c_cflag |= (CS8); /* local modes - choing off, canonical off, no extended functions, * no signal chars (^Z,^C) */ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); /* control chars - set return condition: min number of bytes and timer. * We want read to return every single byte, without timeout. */ raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ /* put terminal in raw mode after flushing */ if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) { perror("tcsetattr failed!\n"); exit(EXIT_FAILURE); } return 0; } 終端窗口大小linux系統(tǒng)提供了一個跟蹤終端大小的功能,,內(nèi)核為每個終端或者是偽終端保存了一個winsize結(jié)構(gòu)體,,這個結(jié)構(gòu)體中保存了當前終端大小的信息。 struct winsize { unsigned short ws_row; unsigned short ws_col; unsigned short ws_xpixel; unsigned short ws_ypixel; }; 作用如下:
/************************************************************************* > File Name: example4.c > Author: AnSwEr > Mail: [email protected] > Created Time: 2015年09月02日 星期三 09時29分00秒 ************************************************************************/ /* * print winsize */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <termios.h> #ifndef TIOCGWINSZ #include <sys/ioctl.h> #endif static void pr_winsize(int fd) { struct winsize size; if(ioctl(fd,TIOCGWINSZ,(char *) &size) < 0) perror("TIOCGWINSZ 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(void) { if(isatty(STDIN_FILENO)==0) { exit(EXIT_FAILURE); } if(signal(SIGWINCH,sig_winch)==SIG_ERR) perror("signal error\n"); pr_winsize(STDIN_FILENO);//打印初始值 for(;;) { pause(); } return 0; } 運行結(jié)果: 總結(jié)本章說明了一些終端操作函數(shù),介紹了一些標志和特殊字符,。對第三篇的串口編程起到了鋪墊的作用,。 反饋與建議
|
|
來自: astrotycoon > 《待分類》