程序間通訊 管道和
fifo
管道,顧名思義就是像水管一樣,水管是用來流通水的,而對與管道來說,做為程序間通訊的一種方式,傳送的是資料而已。對於管道來說,沒有名字,在程式內部以識別符號進行識別,這也就注定了管道只能用於有親緣關係的各個程序間使用。但是這一缺點可以通過
fifo
,又程為有名管道來彌補,先介紹一下管道的基本函式。
#include
intpipe(int fd[2]);
pipe
函式用於管道的建立,函式返回兩個檔案描述符,
fd[0]
用來開啟讀和
fd[1]
用來開啟寫
,管道是單個程序建立的,但是很少在單個程序之間使用,大部分的使用例子如下,父程序建立了乙個管道,通過
fork
呼叫建立了子程序,子程序擁有父程序開啟管道的描述符,然後雙方一方用於從管道中讀出資料,另一方用於從管道中寫入資料,以此來進行程序之間的通訊。
下面寫乙個程式,完成如下功能,客戶服務程式從標準輸入讀取檔案路徑名,然後通過管道傳送給伺服器,然後伺服器呼叫系統函式讀取檔案內容,然後通過管道返回給客戶端,客戶端收到內容以後輸出到標準輸出或者標準錯誤上去,由於雙方都需要讀寫,所以需要使用雙管道進行通訊
#include#include#include#include#include#include#includeint main(int argc,char *argv)
close(fone[0]);
close(ftwo[1]);
client(fone[1],ftwo[0]);//呼叫客戶端程式
waitpid(childfd,null,0);
return 0;
} void server(int readfd,int writefd)
if((fd=open(buf,o_rdonly))<0)//開啟檔案
else
}void client(int writefd,int readfd)
標準i/o函式庫提供了另外函式對管道進行操作
#include
file *popen(const char *command
,const char *type);
int pclose(file *stream);
popen
建立了乙個管道,並啟動另外乙個程序,
command
是shell
命令,如果
type為r
,那麼呼叫程序讀
command
的標準輸出,如果
type是w
,呼叫程序往
command
寫。這個函式使用起來還是比較方便的,個人覺得比exec函式更加容易控制,不過對於popen函式而言,只能重定向標準輸入和標準輸入,如果是標準出錯的話,還是會輸出到程式本書的標準出錯中去的。
管道沒有名字,因此只能用於有親緣關係的程序之間使用,
fifo
類似與管道,先進先出,單項資料流,與管道不同的就是能夠實現無親緣關係之間通訊。
#include
#include
int mkfifo(const char *pathname,mode_t mode);
mkfifo
用於管道的建立
pathname
是unix
路徑名,
mode
用於指定許可權位,定義在
sys/stat.h
中,隱含指定了
o_creat|o_excl
如果沒有的話建立,如過存在的話,返回錯誤。
我們可以用管道重新寫上面的客戶伺服器模式,只需要把建立兩個管道,換成建立兩個
fifo
就行了,
fifo
以pathname
為引數名建立以後開啟進行通訊。
關於管道和
fifo
阻塞的問題。如果乙個函式讀取乙個阻塞的管道或者
fifo
的話,如果該管道裡面沒有資料,那麼讀資料掛起,一直到管道內部有資料為止,如果設定成非阻塞的話,那麼沒有資料的話讀取返回乙個錯誤。
fifo
的阻塞標誌可以在
open
的時候指定。
open(fifo,o_wronly|o_nonblock,0)
;o_nonblock
非阻塞標誌設定,可以進行與或;對於管道來說,沒有名字也就沒有辦法開啟,可以用
fcntl
來獲取和設定
flag=fcntl(fd,f_getfl,0);
用來獲取標誌位 與或以後用
fcntl(fd,f_setfl,flag);
進行設定。
下面就寫乙個無親源關係的客戶伺服器程式,伺服器以公共的名字建立
fifo
,客戶以一定的規則加上自己的
pid建立自己的
fifo
。客戶向伺服器傳送自己
pid和檔名,伺服器返回檔案的內容到客戶的有名管道中,供客戶讀出。
伺服器端程式:
#include#include#include#include#include#include#define flag o_creat|o_excl
#define mode s_irusr|s_iwusr|s_irgrp|s_iwgrp
int main()
fdread=open("/tmp/server.fifo",o_rdonly);
fdwrite=open("/tmp/server.fifo",o_wronly);
read(fdread,buff,1024);
sscanf(buff,"%ld %s",&pid,filename);
sprintf(usrfile,"/tmp/fifo.client.%ld",(long)pid);
if((usrfd=open(usrfile,o_wronly))<0)
if((fdfile=open(filename,o_rdonly))<0)
while((len=read(fdfile,buff,1024))>0)
write(usrfd,buff,len);
close(usrfd);
close(fdfile);
return 0;
}
客戶端程式:
#include#include#include#include#include#include#include#define flag o_creat|o_excl
#define mode s_irusr|s_iwusr|s_irgrp|s_iwgrp
int main()
len=strlen(buf);
write(fdserver,buf,len);
sprintf(buf,"/tmp/fifo.client.%ld",(long)pid);
if(mkfifo(buf,mode)<0)
if((fdclient=open(buf,o_rdonly))<0)
while((len=read(fdclient,buf,1024))>0)
write(1,buf,len);
close(fdserver);
close(fdclient);
return 0;
}
可以實現單伺服器,多使用者模式,伺服器在程式後台執行,前台向伺服器提交請求,伺服器端進行回應。
系統對於管道和
fifo
有如下限制,
open_max
乙個程序在任意時刻可以開啟的最大描述符個數,
pipr_buf
可原子的往乙個管道或者
fifo
的最大資料量
關於這兩個限制,可以通過
sysconf
函式檢視,用過
ulimit
命令和limit
命令進行修改。其中很多規則制約這
fifo
和管道的是否阻塞問題和原子操作問題,關於這方面的討論,才疏學淺,不便多說了。
程序間通訊 管道 命名管道 FIFO
比較類似程序間的生產者 消費者模型。乙個程序向管道中寫入資料,另乙個程序從管道中讀出資料。pipe為無名管道,提供的是一組半雙工通訊方式。pipe會建立兩個檔案物件,乙個索引節點。pipe在核心中會有乙個快取,快取大小可能若干個頁大小。呼叫write像管道裡寫資料時,系統會將資料存於快取,另乙個執行...
程序間通訊 管道通訊(pipe與fifo)
1.程序間通訊 ipc interprocess communication 程序間通訊常用的4中方式 2.pipe管道 pipe管道為匿名管道,就是乙個偽檔案,是乙個核心緩衝區,不占用磁碟空間。管道由讀端與寫端組成,分別對應兩個檔案描述符,管道的讀寫預設是阻塞的。管道的內部是由環形佇列構成的,具有...
程序間通訊 管道
include int pipe int fd 2 返回值 若成功,返回0,若出錯,返回 1經由引數fd返回兩個檔案描述符 fd 0 為讀而開啟,fd 1 為寫而開啟。fd 1 的輸出是fd 0 的輸入。else if pid 0 子程序 else else if pid 0 父程序 printf ...