一、背景
文件與目錄在之前已經學習過了。文件中包含著數據,這些數據可以被讀出、寫入,也可以用以操作。但文件不僅僅是計算機唯一的數據來源,計算機的數據還可以來自於許多的外部設備,比如掃描儀、照相機、鼠標等輸入設備,還有揚聲器、打印機等輸出設備。總之數據來源多種多樣,並不僅侷限於文件。那麼這些外部設備的連接是怎麼樣的呢,其與進程協同工作時的方式(屬性)如何來修改呢。這就是本文所要探究的。
二、外部設備與磁盤文件的聯繫
文件我們都已經很熟悉了,文件通過目錄中的文件名來定位,文件名有一個i-節點與之對應。而i-節點中有文件的屬性且包含著指針列表(此指針列表指向文件的數據內容)。而實際上,外部設備在unix系統中也是以文件的形式存儲的。我們可以從文件中讀數據也可以寫數據。同樣,我們也可以向設備文件寫數據或從中讀出數據。
外部設備的文件一般存儲於/dev中。
這裡顯示的是我的一些設備文件。但是並不是說所有的設備文件必須要存儲於/dev下,並不是這樣的,只是一種約定成俗的習慣,當然也可以在別的目錄下創建設備文件。
三、終端文件
要想看自己的終端文件名,只需輸入tty即可。我的(root)終端文件是這樣的。
而在另一個終端的用戶的終端文件是這樣的。
如此,如我前面所述,如果我可以使用root用戶往/dev/pts/1文件中寫入數據,那麼應該就可以在用戶pf的屏幕上顯示出我所寫入的數據。這樣,我寫了一段代碼用於此功能,實際上這個即是命令write的功能。
如下所示:
這就很清楚的演示了設備文件(終端文件)的操作方法與磁盤文件十分類似,許多的系統調用也都是通用的。
四、外部設備與磁盤文件的不同
第二節講了它們是十分相似的,都是以文件形式來進行操作。並且系統調用往往也是通用的。但它們卻不可能是完全相同的。不同之處主要體現在連接屬性上。對於文件來說,它們與進程進行數據的傳輸是需要緩衝的,緩衝用於文件數據的傳輸上好處很多,最突出的是緩衝可以容錯,而且緩衝是以塊為單位傳輸的,比起字節為單位傳輸,效率要高很多。但這是文件的連接屬性之一,可以開啟也可以關閉。但對於終端來說(以終端為例),當然是不需要緩衝,數據需要儘快的從進程傳輸到終端上來。並且終端也有其許多的連接屬性是文件連接屬性所沒有的,比如回顯、奇偶位、暫停位。
五、終端連接的屬性
文件連接的屬性這裡就不囉嗦了,我主要想討論一下終端連接的屬性。
命令stty用於顯示或修改終端的連接屬性。
顯示全部的終端連接屬性用-a參數。如下所示:
這裡有三種類型的屬性,一種是開關型,一種是數字型、一種是字符控制型。類型是這麼分的,在修改對應類型的屬性時也是不同的。具體如何修改?對於開關型的屬性,只需輸入stty (-)屬性名,括號中的減號可加可不加,若不加,則是打開此屬性開關,若加,則是關閉此屬性開關。對於數字型與字符控制型,只需輸入stty 屬性名 修改值,當然,需要修改什麼屬性就輸入什麼屬性名,而修改值根據自己的需求來定。
六、stty的編程
stty的編程並不複雜,主要會使用兩個系統調用:tcgetattr、tcsetattr。前一個用來將設備文件的信息傳出來,後一個用來將修改過後的信息傳回去。並使用掩碼來進行測試、置位與清除位。
這裡我先編寫了一個簡單的echo的開關文件。結果如下所示:
代碼如下:
#include
#include
#include
int main()
{
struct termios info;
if(tcgetattr(0,&info)==-1){
perror("tcgetattr");
exit(1);
}
else{
if(info.c_lflag&ECHO)
info.c_lflag&=~ECHO;
else
info.c_lflag|=ECHO;
if(tcsetattr(0,TCSANOW,&info)==-1)
perror("tcsetattr");
}
}
自己編寫的stty結果如下:
我這裡還是拿echo來做測試的,因為結果很明顯。
閱讀更多 有理想的代碼dog 的文章