程式間通訊系列--管道

helloxchen發表於2010-11-08

程式間通訊系列--管道

管道可以說是最古老的IPC形式,所謂管道,是指程式間建立的一條通訊的通道,從本質上看,管道是UNIX檔案概念的推廣管道通訊的介質是檔案,先看一下管道的特點:

1.管道的特點:

(1)管道是半雙工的,資料只能向一個方向流動;需要雙方通訊時,需要建立起兩個管道;

(2)無名管道只能用於父子程式或者兄弟程式之間(具有親緣關係的程式);後來發展了FIFO(也稱有名管道)

(3)單獨構成一種獨立的檔案系統:管道對於管道兩端的程式而言,就是一個檔案,但它不是普通的檔案,它不屬於某種檔案系統,而是自立門戶,單獨構成一種檔案系統,並且只存在與記憶體中。

(4)資料的讀出和寫入:一個程式向管道中寫的內容被管道另一端的程式讀出。寫入的內容每次都新增在管道緩衝區的末尾,並且每次都是從緩衝區的頭部讀出資料。

2.無名管道API及操作:

標頭檔案:#include

資料成員:int pipe_fd[2];

管道建立:int pipe(int fd[2])

該函式建立的管道的兩端處於一個程式中間,在實際應用中沒有太大意義,因此,一個程式在由pipe()建立管道後,一般再fork一個子程式,然後透過管道實現父子程式間的通訊(因此也不難推出,只要兩個程式中存在親緣關係,這裡的親緣關係指的是具有共同的祖先,都可以採用管道方式來進行通訊)。

管道讀寫:

管道兩端可分別用描述字fd[0]以及fd[1]來描述,管道讀端:fd[0],管道寫端:fd[1];

讀管道規則:

關閉管道的寫端:close (fd[WRITE]);

讀出:read(fd[READ],string,strlen(string));

讀出後關閉管道的讀端:close(fd[REAd]);

寫管道規則:

關閉管道的讀端:close(fd[REAd]);

寫入:write(fd[WRITE],string,strlen(string));

寫入後關閉管道的寫端:close (fd[WRITE]);

下面練習一個簡單的單管道通訊:

父程式寫資料,子程式負責讀出資料

view plaincopy to clipboardprint?
/**************

* readtest.c *

**************/

#include
#include
#include

#define READ 0
#define WRITE 1

main()
{
int pipe_fd[2];
pid_t pid;
char r_buf[100];
char w_buf[32];
char* p_wbuf;
int r_num;
int cmd;
memset(r_buf,0,sizeof(r_buf));
memset(w_buf,0,sizeof(r_buf));
p_wbuf=w_buf;
if(pipe(pipe_fd)<0)
{
printf("pipe create error ");
return -1;
}

if((pid=fork())==0) //子程式讀
{
close(pipe_fd[WRITE]);
sleep(3); //確保父程式關閉寫端
r_num=read(pipe_fd[READ],r_buf,100);
printf( "read num is %d the data read from the pipe is %s n",r_num,r_buf);
close(pipe_fd[READ]);
exit();
}
else if(pid>0) //父程式寫
{
close(pipe_fd[READ]);
strcpy(w_buf,"hello world!n");
if(write(pipe_fd[WRITE],w_buf,strlen(w_buf))==-1)
printf("parent write overn ");
close(pipe_fd[WRITE]);
printf("parent close fd[WRITE] over n");
sleep(10);
}
}
/**************

* readtest.c *

**************/

#include
#include
#include

#define READ 0
#define WRITE 1

main()
{
int pipe_fd[2];
pid_t pid;
char r_buf[100];
char w_buf[32];
char* p_wbuf;
int r_num;
int cmd;
memset(r_buf,0,sizeof(r_buf));
memset(w_buf,0,sizeof(r_buf));
p_wbuf=w_buf;
if(pipe(pipe_fd)<0)
{
printf("pipe create error ");
return -1;
}

if((pid=fork())==0) //子程式讀
{
close(pipe_fd[WRITE]);
sleep(3); //確保父程式關閉寫端
r_num=read(pipe_fd[READ],r_buf,100);
printf( "read num is %d the data read from the pipe is %s n",r_num,r_buf);
close(pipe_fd[READ]);
exit();
}
else if(pid>0) //父程式寫
{
close(pipe_fd[READ]);
strcpy(w_buf,"hello world!n");
if(write(pipe_fd[WRITE],w_buf,strlen(w_buf))==-1)
printf("parent write overn ");
close(pipe_fd[WRITE]);
printf("parent close fd[WRITE] over n");
sleep(10);
}
}

編譯執行,看到預期結果

3.利用兩個管道進行雙向通訊

(1)建立兩個管道:管道1(父->子),管道2(子->父)

(2)fork()產生子程式

(3)父程式:close(fd1[READ]); close(fd2[WRITE]);

(4)子程式:close(fd1[WRITE]); close(fd2[READ]);

下面做一個練習,是利用雙向通訊實現父子程式協作把整數x從1加到10

view plaincopy to clipboardprint?
#include
#include
#include
#include
#include

#define MAXLINE 1024
#define READ 0
#define WRITE 1

main(void)
{
int x;
pid_t pid;
int pipe1[2],pipe2[2];
/*初始化管道*/
pipe(pipe1);
pipe(pipe2);

pid = fork();
if(pid < 0)
{
printf("create process error!n");
exit(1);
}
if(pid == 0) //子程式
{
close(pipe1[WRITE]);
close(pipe2[READ]);
do
{
read(pipe1[READ],&x,sizeof(int));
printf("child %d read: %dn",getpid(),x++);
write(pipe2[WRITE],&x,sizeof(int));
}while(x<=9);
//讀寫完成後,關閉管道
close(pipe1[READ]);
close(pipe2[WRITE]);
exit(0);
}
else if(pid > 0) //父程式
{
close(pipe2[WRITE]);
close(pipe1[READ]);
x = 1;
//每次迴圈向管道1 的1 端寫入變數X 的值,並從
//管道2 的0 端讀一整數寫入X 再對X 加1,直到X 大於10
do{
write(pipe1[WRITE],&x,sizeof(int));
read(pipe2[READ],&x,sizeof(int));
printf("parent %d read: %dn",getpid(),x++);
}while(x<=9);
//讀寫完成後,關閉管道
close(pipe1[WRITE]);
close(pipe2[READ]);
waitpid(pid,NULL,0);
exit(0);
}
}

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/benny_cen/archive/2009/03/10/3976546.aspx

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24790158/viewspace-1041140/,如需轉載,請註明出處,否則將追究法律責任。

相關文章