管道
由pipe創建,提供一個單向的數據流。
#include <unistd.h>
int pipe(int fd[2]);
// 返回:成功則爲0,出錯則爲-1
該函數返回兩個文件描述符 fd[0] 和 fd[1] 。前者打開來讀,後者打開來寫。
所有管道都是半雙工的,即單向數據流。
全雙工管道
某些系統提供全雙工管道:
1、SVR4的pipe函數。
2、socketpair函數。
/* socketpair - create a pair of connected sockets */
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int socket_vector[2]);
// 返回:成功則爲0,出錯則爲-1
popen 和 pclose 函數
#include <stdio.h>
FILE *popen(const char *command, const char *type);
// 返回:若成功則爲文件指針,若出錯則爲NULL
int pclose(FILE *stream);
// 返回:若成功則爲shell的終止狀態,若出錯則爲-1
popen 函數,它創建一個管道並啓動另外一個進程,該進程要麼從該管道讀出標準輸入,要麼往該管道寫入標準輸出。
command是一個shell命令行,
type:
(1)type爲 r ,調用進程讀進command的標準輸出。
(2)type爲 w,調用進程寫進command的標準輸入。
pclose函數關閉有popen創建的標準I/O流,等待其中的命令終止,然後返回shell的終止狀態。
FIFO
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
// 返回:成功則爲0,出錯則爲-1
pathname是一個路徑名。FIFO的名字。
mode參數指定文件權限位。
在創建出一個FIFO後,它必須或者打開來讀,或者打開來寫。不能打開來既讀又寫,因爲它是半雙工的。
首先,一個描述符能以兩種方式設置成非阻塞。
(1)調用open時可指定O_NONBLOCK標誌。
(2)如果一個描述符已經打開,那麼可以調用fcntl以啓用O_NONBLOCK標誌。
因爲管道沒有open調用,在pipe調用中沒法指定O_NONBLOCK標誌,所以管道必須使用fcntl函數來設置。
下面是關於管道或FIFO的讀出與寫入的若干額外規則。
(1)如果請求讀出的數據量多於管道或FIFO中當前可用數據量,那麼只返回這些可用的數據。
(2)如果請求寫入的數據的字節數小於或等於PIPE_BUF(一個Posix限制值,可以通過getconf命令查看PIPE_BUF的大小),那麼write操作保證的原子的。這意味着,如果有兩個進程差不多同時往同一個管道或FIFO寫,那麼或者先寫入來自第一個進程的所有數據,再寫入來自第二個進程的所有數據,或者顛倒過來。系統不會互相混雜來自這兩個進程的數據。然而,如果請求寫入的數據的字節數大於PIPE_BUF,那麼write操作不能保證是原子的。
(3)O_NONBLOCK標誌的設置對write操作的原子性沒有影響。原子性完全是由所請求字節數是否小於等於PIPE_BUF決定的。然而當一個管道或FIFO設置成非阻塞時,來自write的返回值取決於待寫的字節數以及該管道或FIFO中當前可用空間的大小。
寫入的字節數小於等於PIPE_BUF:
a.如果該管道或FIFO中有足以存放所請求字節數的空間,那麼所有數據字節都寫入。
b.如果該管道或FIFO中沒有足以存放所請求字節數的空間,那麼立即返回一個EAGAIN錯誤。
寫入的字節數大於PIPE_BUF:
a.如果該管道或FIFO中至少有1字節空間,那麼內核寫入該管道或FIFO能容納數目的數據字節,該數目同時作爲來自write的返回值。
b.如果該管道或FIFO已滿,那麼立即返回一個EAGAIN錯誤。
(4)如果向一個沒有爲讀打開着的管道或FIFO寫入,那麼內核將產生一個SIGPIPE信號;
a.如果調用進程既沒有捕獲也沒有忽略該SIGPIPE信號,所採取的默認行爲就是終止該進程。
b.如果調用進程忽略了該SIGPIPE信號,或者捕獲了該信號並從其信號處理程序中返回,那麼write返回一個EPIPE錯誤。
管道和FIFO限制:
系統加於管道和FIFO的唯一限制爲:
OPEN_MAX 一個進程在任意時刻打開的最大描述符數。(Posix要求至少爲16)
PIPE_BUF 可原子地寫往一個管道或FIFO的最大數據量。(Posix要求至少爲512)
定義在頭文件<limits.h>