LLinux系統程式設計(10)——程式間通訊之管道
管道是Linux中很重要的一種通訊方式,是把一個程式的輸出直接連線到另一個程式的輸入,常說的管道多是指無名管道,無名管道只能用於具有親緣關係的程式之間,這是它與有名管道的最大區別。有名管道叫named pipe或者FIFO(先進先出)。
管道具有以下特點:
1、管道是半雙工的,資料只能向一個方向流動;需要雙方通訊時,需要建立起兩個管道;
2、只能用於父子程式或者兄弟程式之間(具有親緣關係的程式);
3、單獨構成一種獨立的檔案系統:管道對於管道兩端的程式而言,就是一個檔案,但它不是普通的檔案,它不屬於某種檔案系統,而是自立門戶,單獨構成一種檔案系統,並且只存在與記憶體中。
4、資料的讀出和寫入:一個程式向管道中寫的內容被管道另一端的程式讀出。寫入的內容每次都新增在管道緩衝區的末尾,並且每次都是從緩衝區的頭部讀出資料。
注意:從管道讀資料是一次性操作,資料一旦被讀,它就從管道中被拋棄,釋放空間以便寫更多的資料。
管道的建立:
#include <unistd.h>
int pipe(int fd[2])
該函式建立的管道的兩端處於一個程式中間,在實際應用中沒有太大意義,因此,一個程式在由pipe()建立管道後,一般再fork一個子程式,然後通過管道實現父子程式間的通訊(因此也不難推出,只要兩個程式中存在親緣關係,這裡的親緣關係指的是具有共同的祖先,都可以採用管道方式來進行通訊)。
管道的讀寫規則:
管道兩端可分別用描述字fd[0]以及fd[1]來描述,需要注意的是,管道的兩端是固定了任務的。即一端只能用於讀,由描述字fd[0]表示,稱其為管道讀端;另一端則只能用於寫,由描述字fd[1]來表示,稱其為管道寫端。如果試圖從管道寫端讀取資料,或者向管道讀端寫入資料都將導致錯誤發生。一般檔案的I/O函式都可以用於管道,如close、read、write等等。
從管道中讀取資料:
如果管道的寫端不存在,則認為已經讀到了資料的末尾,讀函式返回的讀出位元組數為0;
當管道的寫端存在時,如果請求的位元組數目大於PIPE_BUF,則返回管道中現有的資料位元組數,如果請求的位元組數目不大於PIPE_BUF,則返回管道中現有資料位元組數(此時,管道中資料量小於請求的資料量);或者返回請求的位元組數(此時,管道中資料量不小於請求的資料量)。
管道寫端關閉後,寫入的資料將一直存在,直到讀出為止。
下面的程式碼說明管道的讀取規則:
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
main()
{
intpipe_fd[2];
pid_tpid;
charr_buf[100];
charw_buf[4];
char*p_wbuf;
intr_num;
intcmd;
memset(r_buf,0,sizeof(r_buf));
memset(w_buf,0,sizeof(r_buf));
p_wbuf=w_buf;
if(pipe(pipe_fd)<0)
{
printf("pipecreate error\n");
return-1;
}
if((pid=fork())==0)
{
printf("\n");
close(pipe_fd[1]);
sleep(3);//確保父程式關閉寫端
r_num=read(pipe_fd[0],r_buf,100);
printf( "readnum is %d the data read from the pipeis %d\n",r_num,atoi(r_buf));
close(pipe_fd[0]);
exit();
}
elseif(pid>0)
{
close(pipe_fd[0]);//read
strcpy(w_buf,"111");
if(write(pipe_fd[1],w_buf,4)!=-1)
printf("parentwrite over\n");
close(pipe_fd[1]);//write
printf("parentclose fd[1] over\n");
sleep(10);
}
}
向管道中寫入資料:
向管道中寫入資料時,linux將不保證寫入的原子性,管道緩衝區一有空閒區域,寫程式就會試圖向管道寫入資料。如果讀程式不讀走管道緩衝區中的資料,那麼寫操作將一直阻塞。
注:只有在管道的讀端存在時,向管道中寫入資料才有意義。否則,向管道中寫入資料的程式將收到核心傳來的SIFPIPE訊號,應用程式可以處理該訊號,也可以忽略(預設動作則是應用程式終止)。
下面的程式碼說明管道的寫規則:
#include <unistd.h>
#include <sys/types.h>
main()
{
intpipe_fd[2];
pid_tpid;
charr_buf[4];
char*w_buf;
intwritenum;
intcmd;
memset(r_buf,0,sizeof(r_buf));
if(pipe(pipe_fd)<0)
{
printf("pipecreate error\n");
return-1;
}
if((pid=fork())==0)
{
close(pipe_fd[0]);
close(pipe_fd[1]);
sleep(10);
exit();
}
elseif(pid>0)
{
sleep(1); //等待子程式完成關閉讀端的操作
close(pipe_fd[0]);//write
w_buf="111";
if((writenum=write(pipe_fd[1],w_buf,4))==-1)
printf("writeto pipe error\n");
else
printf("thebytes write to pipe is %d \n", writenum);
close(pipe_fd[1]);
}
}
下面的程式碼演示了無名管道用於具有親緣關係的程式間通訊。
#include <unistd.h>
#include <sys/types.h>
main()
{
intpipe_fd[2];
pid_tpid;
charr_buf[4];
char**w_buf[256];
intchildexit=0;
inti;
intcmd;
memset(r_buf,0,sizeof(r_buf));
if(pipe(pipe_fd)<0)
{
printf("pipecreate error\n");
return-1;
}
if((pid=fork())==0)
//子程式:解析從管道中獲取的命令,並作相應的處理
{
printf("\n");
close(pipe_fd[1]);
sleep(2);
while(!childexit)
{
read(pipe_fd[0],r_buf,4);
cmd=atoi(r_buf);
if(cmd==0)
{
printf("child: receive command fromparent over\n now child process exit\n");
childexit=1;
}
else if(handle_cmd(cmd)!=0)
return;
sleep(1);
}
close(pipe_fd[0]);
exit();
}
elseif(pid>0)
//parent:send commands to child
{
close(pipe_fd[0]);
w_buf[0]="003";
w_buf[1]="005";
w_buf[2]="777";
w_buf[3]="000";
for(i=0;i<4;i++)
write(pipe_fd[1],w_buf[i],4);
close(pipe_fd[1]);
}
}
//下面是子程式的命令處理函式(特定於應用):
int handle_cmd(int cmd)
{
if((cmd<0)||(cmd>256))
//suppose child only support 256 commands
{
printf("child:invalid command \n");
return-1;
}
printf("child: the cmd from parent is%d\n", cmd);
return 0;
}
管道的主要侷限性正體現在它的特點上:
只支援單向資料流;
只能用於具有親緣關係的程式之間;
沒有名字;
管道的緩衝區是有限的(管道制存在於記憶體中,在管道建立時,為緩衝區分配一個頁面大小);
管道所傳送的是無格式位元組流,這就要求管道的讀出方和寫入方必須事先約定好資料的格式,比如多少位元組算作一個訊息(或命令、或記錄)等等;
相關文章
- Linux系統程式設計之程式間通訊方式:管道(二)Linux程式設計
- Linux系統程式設計之程式間通訊方式:管道(一)Linux程式設計
- 系統程式設計——管道通訊程式設計
- Linux系統程式設計之程式間通訊方式:命名管道(二)Linux程式設計
- Linux系統程式設計之程式間通訊方式:命名管道(一)Linux程式設計
- Linux系統程式設計(11)——程式間通訊之有名管道Linux程式設計
- linux 程式間通訊之管道Linux
- 溫故之.NET程式間通訊——管道
- 程式間通訊(一)管道
- Linux系統程式設計之程式間通訊方式:訊息佇列Linux程式設計佇列
- PHP多程式程式設計(2):管道通訊PHP程式設計
- Linux系統程式設計之匿名管道Linux程式設計
- linux系統程式設計之管道(一):匿名管道(pipe)Linux程式設計
- linux系統程式設計之管道(三):命令管道(FIFO)Linux程式設計
- Linux 的程式間通訊:管道Linux
- 作業系統程式之間的通訊作業系統
- 【linux】系統程式設計-1-程式、管道和訊號Linux程式設計
- linux程式間通訊--管道(PIPE & FIFO)Linux
- Linux程式間通訊②:有名管道FIFOLinux
- 【IPC程式間通訊之二】管道PipeC程式
- Linux系統程式設計之程式間通訊方式:共享記憶體例項演示Linux程式設計記憶體
- linux系統程式設計之管道(二):管道讀寫規則Linux程式設計
- Linux程式執行緒學習筆記:程式間通訊 之 管道Linux執行緒筆記
- Linux作業系統 程式之間的通訊Linux作業系統
- C#使用匿名管道在本地程式之間進行通訊C#
- Linux系統程式設計—有名管道Linux程式設計
- 3|程式間通訊--有名管道學習筆記筆記
- linux程式間通訊-----管道總結例項Linux
- 作業系統(7)程式間通訊作業系統
- “Linux程式設計”小結(程式間通訊)Linux程式設計
- C#使用命名管道通過網路在程式之間進行通訊C#
- UNIX網路程式設計 卷2:程式間通訊程式設計
- 20.2、python程式間通訊——佇列和管道Python佇列
- Delphi 簡單命名管道在兩個程式間通訊
- Android 程式之間通訊Android
- Linux系統程式設計之命名管道與共享記憶體Linux程式設計記憶體
- 管道流間的通訊
- 程序間通訊(1)-管道