外殼模式(shell)

2021-06-19 20:34:59 字數 3558 閱讀 9814

《系統程式設計師成長計畫》這本書中提到了外殼模式的概念。所謂的外殼模式的作用就是:不需要修改原來的應用程式,而控制它的輸入和輸出(即使用者介面),同時應用程式也不知道外殼的存在。當然這樣理解會比較麻煩,我們就舉個簡單的例子,比如已經存在乙個應用程式,我們想給該應用程式增添乙個新的使用者介面,這裡有兩種選擇:1. 根據該應用程式的內部實現重新編寫乙個使用者介面,但是如果原來的應用程式的使用者介面和內部實現沒有很好的分離,那麼在我們建立新的使用者介面的時候就不可避免的會牽扯到舊的使用者介面;2. 利用外殼模式,外殼模式需要乙個前提條件:應用程式實現了基於終端的使用者介面,即從標準輸入中讀取資料,向標準輸出和標準錯誤輸出顯示結果。這時我們可以把標準輸入、標準輸出和標準錯誤輸出重定向到管道上,向管道裡寫資料來模擬應用程式的輸入和輸出。這樣就實現了外殼模式。

下面是乙個實現自動輸入的程式,通過對該程式的解析,在分析過程中會總結下該程式涉及的有關知識。

#include #include int main(int argc, char * argv)

#include #include int main(int argc, char * argv)

else

; fgets(message, sizeof(message), in);

printf("1: %s\n", message);

fprintf(out, "1234\n");

fflush(out);

fgets(message, sizeof(message), in);

printf("2: %s\n", message);

printf("2: %s\n", message);

fclose(in);

fclose(out);

} return 0;

}

第乙個程式就是乙個main函式,實現的是簡單的輸入輸出。外殼模式的基本原理主要體現在了第二個程式中,這裡面涉及了程序,管道,檔案描述符,輸入輸出流,,execl等一系列的概念,稍後我們會進一步的總結。這裡我們針對這個程式對外殼模式的基本原理進行分析。 

在講解外殼模式的概念的時候,曾提到外殼模式是利用管道模擬標準的輸入輸出。首先我們建立兩個管道(為什麼是兩個呢?在講解管道概念是會提到),兩個管道分別負責兩個程序間的讀寫通訊,其次利用dup2函式重定向子程序的標準輸入輸出,此時我們可以利用建立的兩個管道來模擬子程式中的輸入輸出。

我們逐個解析上面程式用到的概念:

1. 檔案描述符

檔案描述符(file discriptor)在形式上是乙個非負整數。實際上,它是乙個索引值,指向核心為每乙個程序所維護的該程序開啟檔案的記錄表。當程式開啟乙個現有檔案或者建立乙個新檔案時,核心向程序返回乙個檔案描述符。在程式設計中,一些涉及底層的程式編寫往往會圍繞著檔案描述符展開。但是檔案描述符這一概念往往只適用於unix、linux這樣的作業系統。習慣上把0,1,2的檔案描述符定義為標準輸入、標準輸出和標準錯誤輸出,posix 定義了 stdin_fileno、stdout_fileno 和 stderr_fileno 來代替 0、1、2。這三個符號常量的定義位於標頭檔案 unistd.h。這也是上面程式用到的。但是除了linux和unix意外,其他作業系統很難相容檔案描述符,為了解決這個問題,ansi c規範中定義的標準庫的檔案i/o操作。ansi c規範給出了乙個解決方法,就是使用file結構體的指標。事實上,unix/linux平台上的file結構體的實現中往往都是封裝了檔案描述符變數在其中。

提到檔案描述符,就不得不說另外兩個概念:檔案描述符表,檔案表和v節點。

下面用乙個圖可以清晰的表述他們之間的關係

每個程序都有乙個程序表項(包括檔案描述符表),其中每項包含了檔案描述符和檔案指標,未見指標指向檔案表中的某一項,檔案表中某一項中包含了操作該檔案的標誌,偏移量以及v節點,v節點指向了檔案在物理記憶體中的具體位址。從圖中也可以看出,1個v節點對應多個檔案表項,乙個檔案表可以對應多個程序表項。

檔案描述符的生成

open(), open64(), creat(), creat64() // 通過檔案路徑開啟或建立乙個檔案描述符

socket() //建立乙個socket描述符

socketpair() //建立乙個socket對,用於程序間的通訊

pipe() // 建立管道

與單一檔案描述符相關的操作

read(), write() // 對檔案描述符的讀寫,read是指從檔案讀取資料到記憶體,write是把記憶體中的資料寫入到檔案中去。

recv(), send() // 用於tcp通訊的傳送和接受的函式,和read,write類似,但功能更強大

recvmsg(),sendmsg() // 用於udp通訊的傳送和接受函式

sendfile() //公升級版的用於通訊的函式,可以直接通過核心呼叫,減少了到應用程式讀寫兩道操作程式,並降低了記憶體的使用。

lseek(), lseek64() // 定位當前檔案描述符的操作指標

fstat(), fstat64() // 獲取檔案狀態的函式

fchmod()// 改變檔案rwe許可權的函式

fchown()//改變檔案所屬使用者的函式

與複數檔案描述符相關的操作

select(), pselect()

poll()

與檔案描述符表相關的操作

close() // 關閉檔案描述符

dup() //複製乙個檔案描述符

dup2() // 用於重定向檔案描述符

fcntl (f_dupfd) //fcntl()用來操作檔案描述符的一些特性。fcntl 不僅可以施加建議性鎖,還可以施加強制鎖。同時,fcntl還能對檔案的某一記錄進行上鎖,也就是記錄鎖。

fcntl (f_getfd and f_setfd)

改變程序狀態的操作

fchdir() //改變當前工作目錄

mmap() // 建立共享記憶體

與檔案加鎖的操作

flock()

fcntl (f_getlk, f_setlk and f_setlkw)

lockf()

與套接字相關的操作

connect()

bind()

listen()

accept()

getsockname()

getpeername()

getsockopt(), setsockopt()

shutdown()

2. 管道

管道是一種半雙工的程序通訊機制。在另一篇博文程序通訊(一)中有提到。這也是上面提到**中為什麼要用兩個管道了,因為乙個管道只能實現兩個程序間單方向的寫或者讀,使用兩個管道可以實現兩個程序間的互相的讀寫。

23行:與22行類似

最終程式的執行結果是:

因為我的表述能力不夠,不知道這樣說大家能明白麼,可以嘗試的除錯下程式,或者自己查查有關函式的概念,就會明白這個外殼模式demo的基本原理了。

投光燈外殼 LED投光燈外殼特性

在對led燈具關注的過程中,led燈具本身在節能性方面是很好的一種狀態,而在關注led投光燈製作完成的產品外殼的過程中,大家則能夠了解到led投光燈產品在使用的多個部分效果是很不錯的。戶外大型投光燈要達到一定的照明要求,基本都是大功率led晶元。所以led投光燈的防水防塵及散熱三項效能是決定其品質和...

使用外殼變數

就像其它的任何高階語言一樣,在外殼指令碼中使用變數也是十分重要的。1.給變數賦值 在pdksh和bash中,給變數賦值的方法是一樣的,即在變數名後跟著等號和變數值。例如,想要把5賦給變數count,則使用如下的命令 count 5 注意,在等號的兩邊不能有空格 在tcsh中,可以使用如下的命令 se...

Delphi 外殼程式設計( )

摘要 本文介紹了一種有別於通常的windows外殼程式設計方法。採用com技術,通過windows提供的外殼介面實現對其的程式設計。一 引言 都是執行於windows 作業系統 之下的。在 程式開發過程中也經常要在自己的應用程式中加入一些windows系統本身就有的功能,比如檔案的拷貝 刪除 查詢以...