終端I/O有兩種不一樣的工做模式:ios
(1)規範模式:輸入以行單位進行處理,每一個讀請求也最多返回一行。數組
(2)非規範模式:輸入字符不裝配成行。異步
終端設備是由一般位於內核中的終端驅動程序控制的。每一個終端設備都有一個輸入隊列和一個輸出隊列。ide
終端行規程(terminal line discipline)的模塊中進行所有的規範處理。函數
全部能夠檢測和更改的終端設備特性都在termios結構中測試
#include <termios.h> struct termios { tcflag_t c_iflag; /* input flags */ tcflag_t c_oflag; /* output flags */ tcflag_t c_cflag; /* control flags */ tcflag_t c_lflag; /* local flags */ cc_t c_cc[NCCS]; /* control characters */ }
c_cflag支持的常量名稱 CBAUD 波特率的位掩碼 B0 0波特率(放棄DTR) B1800 1800波特率 B2400 2400波特率 B4800 4800波特率 B9600 9600波特率 B19200 19200波特率 B38400 38400波特率 B57600 57600波特率 B115200 115200波特率 EXTA 外部時鐘率 EXTB 外部時鐘率 CSIZE 數據位的位掩碼 CS5 5個數據位 CS6 6個數據位 CS7 7個數據位 CS8 8個數據位 CSTOPB 2箇中止位(不設則是1箇中止位) CREAD 接收使能 PARENB 校驗位使能 PARODD 使用奇校驗而不使用偶校驗 HUPCL 最後關閉時掛線(放棄DTR) CLOCAL 本地鏈接(不改變端口全部者) LOBLK 塊做業控制輸出 CNET_CTSRTS 硬件流控制使能 c_iflag支持的常量名稱 INPCK 奇偶校驗使能 IGNPAR 忽略奇偶校驗錯誤 PARMRK 奇偶校驗錯誤掩碼 ISTRIP 除去奇偶校驗位 IXON 啓動出口硬件流控 IXOFF 啓動入口軟件流控 IXANY 容許字符從新啓動流控 IGNBRK 忽略中斷狀況 BRKINT 當發生中斷時發送SIGINT信號 INLCR 將NL映射到CR IGNCR 忽略CR ICRNL 將CR映射到NL IUCLC 將高位狀況映射到低位狀況 IMAXBEL 當輸入太長時回覆ECHO c_cc 支持的常量名稱 VINTR 中斷控制,對應鍵爲CTRL+C VQUIT 退出操做,對應鍵爲CRTL+Z VERASE 刪除操做,對應鍵爲Backspace(BS) VKILL 刪除行,對應鍵爲CTRL+U VEOF 位於文件結尾,對應鍵爲CTRL+D VEOL 位於行尾,對應鍵爲Carriage return(CR) VEOL2 位於第二行尾,對應鍵爲Line feed(LF) VMIN 指定了最少讀取的字符數 VTIME 指定了讀取每一個字符的等待時間 串口控制函數 Tcgetattr 取屬性(termios結構) Tcsetattr 設置屬性(termios結構) cfgetispeed 獲得輸入速度 Cfgetospeed 獲得輸出速度 Cfsetispeed 設置輸入速度 Cfsetospeed 設置輸出速度 Tcdrain 等待全部輸出都被傳輸 tcflow 掛起傳輸或接收 tcflush 刷清未決輸入和/或輸出 Tcsendbreak 送BREAK字符 tcgetpgrp 獲得前臺進程組ID tcsetpgrp 設置前臺進程組ID
獲取和設置termios結構fetch
#include <termios.h> #include <unistd.h> int tcgetattr(int fd, struct termios *termios_p); int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
兩個函數的返回值:成功0,出錯-1
fd:若fd沒有引用中斷設備則出錯返回-1
optional_actions:指定何時新的終端屬性起做用。
TCSANOW 更改當即發生
TCSADRAIN 發送了全部輸出後更改才發生。若更改輸出參數則應使用此選項
TCSAFLUSH 發送了全部輸出後更改才發生。更進一步,在更改發生時未讀的全部輸入數據都被丟棄(沖洗)
例子:ui
1 #include "apue.h" 2 #include <termios.h> 3 4 int main(void) 5 { 6 struct termios term; 7 long vdisable; 8 9 if(isatty(STDIN_FILENO) == 0) 10 err_quit("standard input is not a terminal device"); 11 12 if((vdisable = fpathconf(STDIN_FILENO, _PC_VDISABLE)) < 0) 13 err_quit("fpathconf error or _POSIX_VDISABLE not in effect"); 14 15 if(tcgetattr(STDIN_FILENO, &term) < 0) /* fetch tty state */ 16 err_sys("tcgetattr error"); 17 18 term.c_cc[VINTR] = vdisable; /* disable INTR character */ 19 term.c_cc[VEOF] = 2; /* EOF is Control-B */ 20 21 if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) < 0) 22 err_sys("tcsetattr error"); 23 24 exit(0); 25 }
該程序先用 isatty 函數來測試 STDIN_FILENO 描述符所指向的文件是不是終端設備,若是測試的文件描述符是指向一個終端設備的話則返回1,不然返回0。spa
而後使用函數 fpathconf 獲取系統中的 _PC_VDISABLE 的值,將這個值保存在 c_cc 數組中的相應位置就能夠禁止使用這個位置所表明的特殊字符。3d
接着咱們調用 tcgetattr 函數用來獲取終端IO的屬性,而後設置 c_cc 數組的 VINTR 的位置爲 _PC_VDISABLE,表示禁止使用中斷符號CTRL+C。而將VEOF的位置的值更改成2,即表示將文件的結束符號修改成CTRL+B,同理若是要修改成CTRL+A,則這個地方的值爲1。
設置波特率
#incldue <termios.h> speed_t cfgetispeed(const struct termios *termios_p); spee_t cfgetospeed(const struct termios *termios_p);
兩個函數的返回值:波特率值 int cfsetispeed(struct termios *termios_p, speed_t speed); int cfsetospeed(struct termios *termios_p, speed_t speed);
兩個函數的返回值:成功0,出錯-1
termios_p:指向termios的指針
speed:波特率速度,是下列常量B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400
使用這些函數時,必須認識到輸入、輸出波特率是存儲在設備的termios結構中的。在調用兩個cfget函數中的任意一個以前,要先用tcgetattr得到設備的termios結構。
在調用cfset函數中的任意一個後,要作的就是在termios結構中設置波特率,爲了更改到設備中,應當調用tcseattr函數。
行控制函數
#include <termios.h> #include <unistd.h> int tcdrain(int fd); //等待全部寫入fd中的數據輸出 int tcflow(int fd, int action); //掛起fd上的數據傳輸或接收 int tcflush(int fd, int queue_selector); //丟棄要寫入fd,但還沒有傳輸的數據,或者收到還沒有讀取的數據 int tcsendbreak(int fd, int duration); //傳送連續0值比特流,持續一段時間,若是終端使用異步串行數據傳輸的話
4個函數返回值:成功0,出錯-1
fd:引用一個終端設備
action:
TCSANOW:不等數據傳輸完畢就當即改變屬性。
TCSADRAIN:等待全部數據傳輸結束才改變屬性。
TCSAFLUSH:清空輸入輸出緩衝區才改變屬性。
queue_selector:
TCIFLUSH:刷新收到的數據可是不讀
TCOFLUSH:刷新寫入的數據可是不傳送
TCIOFLUSH:同時刷新收到的數據可是不讀,而且刷新寫入的數據可是不傳送
duration:若是是0,至少傳輸0.25秒,不會超過0.5秒。非零,他發送的時間長度由實現定義
大多數控制終端的名字是/dev/tty,POSIX.1提供了一個運行時函數,可用來肯定控制終端的名字。
#include <stdio.h> char *ctermid(char *s);
返回值:成功返回指向控制終端名的指針,出錯返回指向空字符串的指針
s:若是非空,則被認爲是一個指針,長度至少爲L_ctermid字節的數組,進程的控制終端名存儲在該數組中。
若是文件描述符引用一個終端設備,則isatty返回真。
ttyname返回的是在該文件描述符上打開的中斷設備的路徑名
#include <unistd.h> int isatty(int fd); 返回值:若爲終端設備,返回1(真),不然返回0(假) char *ttyname(int fd); 返回值:指向終端路徑名的指針,出錯返回NULL fd:終端關聯的描述符
內核爲每一個終端和僞終端都維護了一個winsize結構:
struct winsize { unsigned short ws_row; unsigned short ws_col; unsigned short ws_xpixel; unsgined short ws_ypixel; };