原文地址:http://blog.chinaunix.net/uid-27034868-id-3394243.html
管道是一種兩個進程間進行單向通信的機制毅臊。因為管道傳遞數(shù)據(jù)的單向性熬苍,管道又稱為半雙工管道柴底。管道的這一特點決定了器使用的局限性梦裂。管道是Linux支持的最初Unix IPC形式之一年柠,具有以下特點:
***數(shù)據(jù)只能由一個進程流向另一個進程(其中一個讀管道冗恨,一個寫管道)味赃;如果要進行雙工通信心俗,需要建 立兩個管道城榛。
***管道只能用于父子進程或者兄弟進程間通信狠持。,也就是說管道只能用于具有親緣關系的進程間通信甜刻。
除了以上局限性得院,管道還有其他一些不足尿招,如管道沒有名字(匿名管道)就谜,管道的緩沖區(qū)大小是受限制的丧荐。管道所傳輸?shù)氖菬o格式的字節(jié)流虹统。這就需要管道輸入方和輸出方事先約定好數(shù)據(jù)格式车荔。雖然有那么多不足忧便,但對于一些簡單的進程間通信珠增,管道還是完全可以勝任的。
使用管道進行通信時巍举,兩端的進程向管道讀寫數(shù)據(jù)是通過創(chuàng)建管道時懊悯,系統(tǒng)設置的文件描述符進行的定枷。從本質上說欠窒,管道也是一種文件岖妄,但它又和一般的文件有所不同荐虐,可以克服使用文件進行通信的兩個問題福扬,這個文件只存在內存中铛碑。
通過管道通信的兩個進程汽烦,一個進程向管道寫數(shù)據(jù)撇吞,另外一個從中讀數(shù)據(jù)牍颈。寫入的數(shù)據(jù)每次都添加到管道緩沖區(qū)的末尾煮岁,讀數(shù)據(jù)的時候都是從緩沖區(qū)的頭部讀出數(shù)據(jù)的人乓。
#include
int pipe(int pipefd[2]);
(匿名)管道兩端分別用描述符pipefd[0]及pipefd[1]來描述色罚。需要注意的是戳护,管道兩端的任務是固定的腌且,一端只能用于讀铺董,有描述符pipefd[0]表示精续,稱其為管道讀端重付;另一端只能用于寫弓颈,由描述符pipe[1]來表示删掀,稱其為管道寫端橘蜜。該函數(shù)創(chuàng)建的管道的兩端處于一個進程中間计福,在實際應用中沒有太大意義象颖,因此,一個進程在由pipe()創(chuàng)建管道后陶冷,一般再fork一個子進程埂伦,然后通過管道實現(xiàn)父子進程間的通信。在此不再作多介紹基跑,下面看看有名管道吧媳否。
管道的一個不足之處就是沒有名字,因此室抽,只能用于具有親緣關系的進程間通信晓折,在有名管道(name pipe或FIFO)提出后漓概,該限制得到了解決。FIFO不同與管道之處在與她提供一個路徑名與之關聯(lián)觅彰,以FIFO的文件形式存儲在文件系統(tǒng)中。有名管道是一個設備文件飒责,因此,即使進程與創(chuàng)建FIFO的進程不存在親緣關系拾并,只要可以訪問該路徑个榕,就能夠通過FIFO相互通信了凰萨。值得注意的是FIFO(First In First Out)總是按照先進先出的原則工作胖眷,第一個被寫入的數(shù)據(jù)首先從管道中讀出。
在Linux中我們經常使用管道重定向數(shù)據(jù)囚枪。比如:
下面介紹一下創(chuàng)建有名管道的系統(tǒng)調用沛鸵,有兩個疾捍,mknod和mkfifo
#include?
#include?
int mknod(const char *pathname, mode_t mode, dev_t dev);
int?mkfifo(?const?char?*pathname,?mode_t?mode?);
函數(shù)mknod參數(shù)中pathname為創(chuàng)建有名管道的全路徑名,mode為創(chuàng)建有名管道的模式,指明其存取權限疲酌;dev為設備值,該值取決于文件創(chuàng)建的種類,它只在創(chuàng)建設備文件是才會用到。這兩個函數(shù)調用成功都返回0执赡,否則返回-1.
讀寫有名管道:
#include?
ssize_t?read?(int?fd?,?void?*?buf?,?size_t?nbytes)
ssize_t?write?(int?fd?,?void?*?buf?,?size_t?nbytes)
接下來給大家演示一下通過有名管道通信的聊天程序跌帐。即舌。盯仪。
點擊(此處)折疊或打開
//李四.c
#include
#include
#include
#include
#include
#include
#include
#include
#define FIFO_READ"writefifo"http://另外一個程序只要把本程序
#define FIFO_WRITE"readfifo"http://拷貝一份然后調換這兩個宏即可
#define BUF_SIZE????1024
intleft=0;
void*read_buf()
{
intrfd=-1;
char buf[BUF_SIZE]={'\0'};
inti;
printf("等待對方……\n");
while((rfd=open(FIFO_READ,O_RDONLY))==-1){
sleep(1);
}
while(left!=1){
//printf("i=%d ",i++);
intlen=read(rfd,buf,BUF_SIZE);
if(len>0){
buf[len]='\0';
if(strcmp(buf,"不理你了")==0){
printf("\n對方已經走開!\n");
left=1;
break;
//exit(0);
}
for(i=0;i
printf("\b");
printf("對方:%s\n",buf);
printf("我:");
fflush(stdout);
}
}
close(rfd);
returnNULL;
}
void*write_to()
{
intwfd;
char buf[BUF_SIZE];
intlen;
umask(0);
if(mkfifo(FIFO_WRITE,S_IFIFO|0666)){
printf("Can't create FIFO %s because %s",FIFO_WRITE,
strerror(errno));
exit(1);
}
umask(0);
wfd=open(FIFO_WRITE,O_WRONLY);
if(wfd==-1){
printf("open FIFO %s error: %s",FIFO_WRITE,strerror(errno));
exit(1);
}
while(left!=1){
printf("我: ");
fgets(buf,BUF_SIZE,stdin);
buf[strlen(buf)-1]='\0';
if(strcmp(buf,"不理你了")==0||left==1){
write(wfd,buf,strlen(buf));//通知對方
close(wfd);
unlink(FIFO_WRITE);
exit(0);
}
write(wfd,buf,strlen(buf));
fflush(stdin);
}
}
intmain(intargc,char*argv[])
{
pthread_t thIDr,thIDw;
pthread_create(&thIDr,NULL,(void*)read_buf,NULL);
pthread_create(&thIDw,NULL,(void*)write_to,NULL);
pthread_join(thIDr,NULL);
pthread_join(thIDw,NULL);
return 0;
}
學以置用全景,呵呵耀石,效果如下:
注:本博客的文章除注明有“轉載”字樣的外,均為原創(chuàng)爸黄,歡迎轉載滞伟,請注明文字出處,謝謝炕贵!