管道是一種最古老也是最基本的系統IPC形式,管道就像現實中的水管,水就像數據,它是消息傳遞的一種特殊方式,管道機制必須提供三方面的協調能力:互斥、同步和確定對方的存在。在Linux中是一種使用非常頻繁的通信機制。從本質上說,管道也是一種文件,但它又和一般的文件有所不同;所有的Linux系統都提供此種通信機制。
管道有以下局限性:
1、它是半雙工的,即數據一個管道上的數據只能在一個方向上流動,如果要實現雙向通信,就必須在兩個進程之間建立兩個管道;
2、管道的緩沖區是有限的(管道制存在于內存中,在管道創建時,為緩沖區分配一個頁面大小);
3、管道所傳送的是無格式字節流,這就要求管道的讀出方和寫入方必須事先約定好數據的格式,比如多少字節算作一個消息(或命令、或記錄)等等。
4、管道只能在具有公共祖先的兩個進程之間使用等等;
通常,進程會先調用pipe函數產生管道,接著調用fork()函數,fork函數會將父進程的相關數據結構繼承到子進程中,這樣就使子進程中的文件描述符表中的fd[0]和fd[1]指向父進程所指向的管道文件,這樣就能實現兩個進程之間的通信。
管道通信分為無名管道個命名管道,其中,無名管道:
int pipe(int filedes[2]);
返回值:成功,返回0,否則返回-1。參數數組包含pipe使用的兩個文件的描述符。fd[0]:讀管道,fd[1]:寫管道。
必須在fork()中調用pipe(),否則子進程不會繼承文件描述符。兩個進程不共享祖先進程,就不能使用pipe。但是可以使用命名管道。
命名管道FIFO:
管道最大的劣勢就是沒有名字,只能用于有一個共同祖先進程的各個進程之間。FIFO代表先進先出,單它是一個單向數據流,也就是半雙工,和無名管道不同的是:每個FIFO都有一個路徑與之關聯,從而允許無親緣關系的進程訪問。
int mkfifo(const char *pathname, mode_t mode);
這里pathname是路徑名,mode是sys/stat.h里面定義的創建文件的權限.
命名管道具有很好的使用靈活性,表現在:
管道是一種把兩個進程之間的標準輸入和標準輸出連接起來的機制,從而提供一種讓多個進程間通信的方法,當進程創建管道時,每次都需要提供兩個文件描述符來操作管道。其中一個對管道進行寫操作,另一個對管道進行讀操作。對管道的讀寫與一般的IO系統函數一致,使用write()函數寫入數據,使用read()讀出數據。它是由內核管理的一個緩沖區,它的一端連接一個進程的輸出,另一端連接一個進程的輸入。管道的緩沖區不需要很大,它被設計為環形的數據結構,當兩個進程都終止后,管道的生命周期也會被結束。
注:只有在管道的讀端存在時,向管道中寫入數據才有意義,具有親緣關系通過進程間通信,用戶自己創建管道,完成讀寫操作,管道和FIFO的數據是字節流,應用程序之間必須事先確定特定的傳輸"協議",同時,父子進程在運行時,它們的先后次序并不能保證。因此,為了保證父子進程已經關閉了相應的文件描述符,可在兩個進程中調用sleep()函數達成。