最近在想一個問題,關於進程間通信的問題,我們都知道進程間可以通過管道通信,但是為什么進程間可以通過管道通信呢?管道通信的機制又是什么呢?我想很多人應該沒有去思考過,下面我來講講我對管道通信機制的理解。
如果兩個不相關的進程打開同一個文件,一個只讀方式開打,一個只寫方式打開,不就相當於創建了一個管道了,進程A往里面寫,進程B讀,同樣實現進程間通信。管道其實也一樣。
一般的管道,只能在父子進程間進行通信,為什么?因為管道實現的進程間通信是在父進程fork()出子進程時,子進程會繼承父進程的文件描述符表,而這個文件描述符表里記錄了所有父進程打開的文件,所以子進程也繼承了父進程打開的文件,所以父子進程可以通過同一個文件描述符去訪問同一個文件(但是不相干的進程文件描述符相同也不代表同一個文件),而管道就是建立在文件描述符上的,建立一個管道必須和兩個文件描述符相關,一個可以賦予可讀權限,一個可以賦予可寫權限,但是這兩個文件描述符其實都和同一個文件關聯,所以你通過不同的文件描述符去訪問這個文件時,可以獲得不同的訪問權限,如果在父子進程中,在父進程將fd[0]為可讀,fd[1]可寫,而子進程fd[0]可讀,fd[1]可寫,那么這個管道就將父子進程連起來,如下圖所示:
創建文件描述符的方法有:
進程獲取文件描述符最常見的方法是通過本機子例程open或create獲取或者通過從父進程繼承。后一種方法允許子進程同樣能夠訪問由父進程使用的文件。文件描述符對於每個進程一般是唯一的。當用fork子例程創建某個子進程時,該子進程會獲得其父進程所有文件描述符的副本,這些文件描述符在執行fork時打開。在由fcntl、dup和dup2子例程復制或拷貝某個進程時,會發生同樣的復制過程。
下面有兩個衍生的問題:
問題1:實現兩個進程都能向同一個socket中寫數據, 也就是服務器端只accept一次就可以把兩個進程寫的數據全部接收到, 傳輸過來的數據的先后順序不用管.
問題2: 我在一個程序里打開了一個文件。將文件描述符傳給了另外一個程序。在另一個文件中能否對這個文件描述符進行操作。兩個程序不是fork出來的。是完全2個獨立的程序。
解決命名管道。
關於文件描述符的詳述如下:
在Linux中,進程是通過文件描述符(file descriptors,簡稱fd)而不是文件名來訪問文件的,文件描述符實際上是一個整數。Linux中規定每個進程能最多能同時使用NR_OPEN個文件描述符,這個值在fs.h中定義,為1024*1024(2.0版中僅定義為256)。
每個文件都有一個32位的數字來表示下一個讀寫的字節位置,這個數字叫做文件位置。每次打開一個文件,除非明確要求,否則文件位置都被置為0,即文件的開始處,此后的讀或寫操作都將從文件的開始處執行,但你可以通過執行系統調用LSEEK(隨機存儲)對這個文件位置進行修改。Linux中專門用了一個數據結構file來保存打開文件的文件位置,這個結構稱為打開的文件描述(open file description)。這個數據結構的設置是煞費苦心的,因為它與進程的聯系非常緊密,可以說這是VFS中一個比較難於理解的數據結構。
file結構中主要保存了文件位置,此外,還把指向該文件索引節點的指針也放在其中。file結構形成一個雙鏈表,稱為系統打開文件表,其最大長度是NR_FILE,在fs.h中定義為8192。
file結構在include\linux\fs.h中定義如下:
struct file { struct list_head f_list; /*所有打開的文件形成一個鏈表*/ struct dentry *f_dentry; /*指向相關目錄項的指針*/ struct vfsmount *f_vfsmnt; /*指向VFS安裝點的指針*/ struct file_operations *f_op; /*指向文件操作表的指針*/ mode_t f_mode; /*文件的打開模式*/ loff_t f_pos; /*文件的當前位置*/ unsigned short f_flags; /*打開文件時所指定的標志*/ unsigned short f_count; /*使用該結構的進程數*/ unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; /*預讀標志、要預讀的最多頁面數、上次預讀后的文件指針、預讀的字節數以及預讀的頁面數*/ int f_owner; /* 通過信號進行異步I/O數據的傳送*/ unsigned int f_uid, f_gid; /*用戶的UID和GID*/ int f_error; /*網絡寫操作的錯誤碼*/ unsigned long f_version; /*版本號*/ void *private_data; /* tty驅動程序所需 */ };
內核中,對應於每個進程都有一個文件描述符表,表示這個進程打開的所有文件。文件描述表中每一項都是一個指針,指向一個用於描述打開的文件的數據塊———file對象,file對象中描述了文件的打開模式,讀寫位置等重要信息,當進程打開一個文件時,內核就會創建一個新的file對象。需要注意的是,file對象不是專屬於某個進程的,不同進程的文件描述符表中的指針可以指向相同的file對象,從而共享這個打開的文件。file對象有引用計數,記錄了引用這個對象的文件描述符個數,只有當引用計數為0時,內核才銷毀file對象,因此某個進程關閉文件,不影響與之共享同一個file對象的進程.