[程設] Linux C 的file descriptor以及pipe操作相關筆記(上)

這篇主要是在紀錄一些pipe操作時的注意事項

作業一的內容是實做一個遠端操作的shell,可以利用telnet登入之後進行基本的shell指令操作(執行命令,pipe操作,重新導向),這篇筆記著重在pipe操作的部份

先簡單的描述一下fd_table的觀念,不過這些是我自己的理解,我不敢保證一定正確。

在Unix-like下,會盡量把裝置視為一個檔案,也就是說,所有對該裝置的讀取與寫入都可以視為對檔案進行讀取與寫入,而每個檔案都會有一個編號,也就是file descriptor,程式在讀取與寫入時指明目標file descriptor後,即可對該檔案進行所需要的操作。 每個程式執行時,Linux核心會自動提供一個file descriptor的table,負責紀錄這些檔案操作的紀錄,一般程式執行時,預設會開啟三個檔案,stdin,stdout,stderr,程式的標準輸入輸出(scanf / printf cin cout之類的),實際上就是對stdin,stdout進行讀取與寫入。當你在開檔的時候,程式會在file descriptor上面紀錄所需的資料後,將該筆資料的編號回傳給你,以後就可以對這個編號進行讀取或寫入。而pipe也是如此,呼叫pipe指令時,Linux核心內會建立一個緩衝區,並在file descriptor table 中開啟兩個新的號碼,在這之後就可以利用這兩個號碼對資料進行讀取與寫入,寫入時會寫入到pipe裡的緩衝區,讀取時就是從緩衝區裡面取出資料,緩衝區的部份由Linux核心提供支援,程式撰寫者並不需要去煩惱該部份的運作。

以上段落可以簡化成幾個重點

1.每個程式都有一張表,紀錄許多檔案編號,以及該檔案編號對應的資料,此部份由Linux核心支援,使用者不需要(也沒辦法)去知道該部份的實際運作情形

2.開檔的時候實際上就是在這張表裡面新增一筆資料,在讀寫檔案的時候必須同時提供該筆資料的編號

3.每個程式預設開啟stdin,stdout,stderr這三個檔案,分別置放於這張表的第0,1,2位置

相關的指令有pipe(呼叫system call建立pipe之後回傳file descriptor編號),dup2(複製file desciptor),詳細用法可以google,網路上資料很多

將其他筆檔案描述資料複製到fd_table的第0~2個位置以後,就可以將標準輸入輸出從鍵盤螢幕改到該檔案描述資料上,(例如說:我開了一個檔案編號是3,那我將第三個位置複製到第0個位置之後,所有從鍵盤輸入的資料就會改從由該檔案讀取資料),利用這個方法來完成shell裡面的資料重新導向,程序之間的溝通之類的玩意。

實做上必須注意以下幾個重點

1.有複製,就要有關閉,一個dup2搭一個close,保持file descriptor的單純性
(此為血淚經驗談,自己實做就知道…)

2.fork出去的程式,沒用到的file descriptor一定要記得關
舉例來說,本來shell主程式裡面有一個pipe,若是此時fork出子程序來exec指令,主程序下wait指令等待子程序執行完畢且主程序沒有關閉pipe,則主程序會卡住。因為當fork的時候,一個pipe實際上會變成兩個pipe,當指派子程序接收pipe資料的時候,如果還有其他pipe沒有關閉,則子程序會判定pipe資料流尚未結束,而繼續癡癡等待輸入,若是主程序有pipe沒關閉的話,結果就是主程序在等子程序結束,子程序又在等待主程序的pipe輸入資料,造成死結。

本篇發表於 程設筆記, Uncategorized 並標籤為 。將永久鏈結加入書籤。

1 Responses to [程設] Linux C 的file descriptor以及pipe操作相關筆記(上)

  1. 邱子翔 說道:

    實作出現po主同樣症狀 多謝po主經驗分享

發表留言