popen是高級的函數,底層的使用pipe函數。
pipe這個函數在兩個程序之間傳遞數據不需要啟動一個shell來解釋請求的命令。它同時提供了對讀寫數據的更多控制。
頭文件: unstd.h
int pipe(int file_descriptor[2]);
pipe 函數的參數是一個由兩個整數類型的文件描述符組成的數組的指針。該函數在數組中填上兩個新的文件描述符返回0,如果失敗就會返回-1并設置errno來表明失敗的原因。
linux手冊上定義的一些錯誤:
(1)EMFILE: 進程使用的文件描述符過多
(2)ENFILE: 系統的文件表已經滿
(3)EFAULT: 文件描述符無效
兩個返回的問阿金描述符以一種特殊的方式連接起來。寫到file_descriptor[1] 的所有數據都可以從file_descriptor[0]讀回來。數據基于先進先出的原則(FIFO)進行處理,這意味著如果你把字節1,2,3寫到file_descriptor[1],從file_descripter[0]讀取到的數據也會是1,2,3.這個和棧有點不一樣,棧是后進先出[LIFO];這個應該算是隊列。
特別要注意:這里使用的是文件描述符而不是文件流,所以我們必須用底層的read和write調用阿里訪問數據,而不是用文件流庫函數fread 和fwrite。
PS:底層的有底層的方法,底層不可能直接通過流來處理,而是通過文件描述符。
管道寫入和讀取代碼程序
這個程序用數組file_pipes[]中的兩個文件描述符創建了一個管道。然后它用文件描述符file_pipes[1]向管道寫數據,在從file_pipes[0]讀取數據。注意,管道有一些內置的緩存區,它在write和read調用之間保存數據。
如果你嘗試用file_descriptor[0]寫數據或用file_descriptor[1]讀數據,其后果未在文檔中明確定義,所以其行為可能會非常奇怪,并且隨著系統的不同,其行為可能發生變化。在我的系統上,這樣的調用將失敗并且返回-1,這至少能夠說明這種錯誤比較容易發現的。
咋一看:管道沒有什么特別,可以用一個簡單的文件完成;
管道真正的優勢在于:當你兩個進程之間傳遞數據的時候。
(12章)當程序用fork調用創建新進程時候,原先打開的文件描述符忍將保持打開狀態。如果在原先的進程中創建一個管道。然后在調用fork創建新繼承,我們即可通過管道在兩個進程之間傳遞數據。
實驗解析:
這個程序首先用pipe調用創建一個管道,接著用fork調用創建一個新進程。如果fork調用成功,父進程就寫數據到管道中,而子進程從管道中讀取數據。父進程都在只調用了一次write 或read之后就會退出。如果父進程在子進程之前退出,就會在兩部分輸出之間看到shell提示符(shell上運行)。
表面上:這個程序和上面的程序例子很相似,但是實際上這個例子中我們往前跨除了一大步,我們可以在不同的進程之間進行了讀寫操作了。
PS: pipe 的作用:
(1)一個是和文件寫入和讀取有點類似
(2)重點:可以在有親緣關系的進程之間傳遞數據。