apue 第18章 終端I/O

終端I/O有兩種不一樣的工做模式:ios

(1)規範模式:輸入以行單位進行處理,每一個讀請求也最多返回一行。數組

(2)非規範模式:輸入字符不裝配成行。異步

 

終端設備是由一般位於內核中的終端驅動程序控制的。每一個終端設備都有一個輸入隊列和一個輸出隊列。ide

  • 若是打開了回顯,輸入隊列和輸出隊列之間有一個隱含的鏈接
  • 輸入隊列有一個MAX_INPUT的有限值
  • 還有一個MAX_CANON,限制輸入行的最大字節數
  • 輸出隊列也是有限的,可是當它快要滿的時候,內核會讓它休眠,直到有可用空間

終端行規程(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 }
CTRL+B

     該程序先用  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;
};
相關文章
相關標籤/搜索