管道
管道由於傳遞數據只能單向傳遞,因此又稱半雙工管道,它是一種兩個進程間進行單向通信的機制.
侷限性:
*數據只能由一個進程流向另一個進程,若要進行全雙工通信,則需建立兩個管道.
*管道只能用於具有親緣關係的進程間通信.
*管道無名字.
*管道的緩衝區大小受限制.
*管道所傳遞的是無格式的字節流,這就要求管道的輸入和輸出事先約定好數據格式.
使用管道進行通信時,兩端的進程向管道讀寫數據是通過創建管道時,系統設置的文件描述符進行的.
管道是一個特殊的文件,這個文件只存在於內存中.在創建管道時,系統爲管道分配一個頁面作爲數據緩衝區,進行管道通信的兩個進程通過讀寫這個緩衝區來進行通信.
寫入的數據每次添加在管道緩衝區的末尾,讀數據時都是從緩衝區的頭部讀出數據.
管道的創建
linux下創建管道可以通過函數pipe完成,該函數如果調用成功返回0,並且數組中將包含兩個新的文件描述符.如果有錯誤發生,則返回-1.
管道兩端分別用描述符fd[0]及fd[1]來描述.
管道兩端的任務固定.fd[0]爲管道讀端,fd[1]爲管道寫端.
管道是一種文件,創建成功後就可以作爲一般文件來使用,因此對文件操作的I/O函數都可以用於管道,如read(),write()等.
管道的一般用法
進程在使用fork函數創建子進程前先創建一個管道,該管道用於在父子進程間通信.然後創建子進程,之後父進程關閉管道讀端,子進程關閉管道寫端,父進程負責向管道寫數據,子進程負責讀數據.也可以父進程關閉管道寫端,子進程關閉管道讀端.
管道的讀寫
從管道中讀數據
要讀取管道中數據的進程要關閉管道寫端fd1,同時向管道寫數據的進程應關閉讀端fd0.(因爲是用於具有親緣關係的進程間通信,所以共享文件描述符).使用前,應及時關閉不需要的另一端,避免錯誤的發生.
進程在管道的讀端讀數據時,
1.如果管道寫端不存在,則讀進程認爲已經讀到數據的末尾,讀函數返回讀出的字節數爲.
2.若管道寫端存在,
(1)且請求讀取的字節數大於PIPE_BUF,則返回管道中所有數據,
(2)如果不大於PIPE_BUF,則返回管道中現有的所有數據(管道中數據量小於請求的數據量). 或返回請求的字節數(管道中數據量大於等於請求的數據量)
向管道中寫數據
如果某進程希望向管道中寫入數據,那麼該進程應關閉讀端fd0文件描述符,同時管道另一端的進程關閉fd1.
向管道寫入數據時,linux不保證寫入的原子性.
>原子性:操作在任何時候都不能被任何原因打斷,操作要麼不做要麼就一定完成.
管道緩衝區一有空閒區域,寫進程就會試圖向管道寫入數據,若讀進程不讀走緩衝區的數據,則寫操作一直被阻塞等待.
在寫管道時,如果請求的字節數小於等於PIPE_BUF,則多個進程對同一管道的寫操作不會交錯進行,但如果有多個進程同時寫一個管道,且某些進程要求寫的字節數超過PIPE_BUF所能容納時,則多個寫操作的數據可能會交錯.
>只由管道讀端存在時,向管道中寫入數據纔有意義.否則,向管道中寫入數據的進程將收到內核傳來的SIGPIPE信號,如果忽略或撲捉該信號並從其處理程序返回,則write出錯,錯誤碼爲EPIPE.