原文地址:http://blog.chinaunix.net/uid-27034868-id-3394243.html
管道是一種兩個(gè)進(jìn)程間進(jìn)行單向通信的機(jī)制。因?yàn)楣艿纻鬟f數(shù)據(jù)的單向性,管道又稱為半雙工管道。管道的這一特點(diǎn)決定了器使用的局限性。管道是Linux支持的最初Unix IPC形式之一,具有以下特點(diǎn):
***數(shù)據(jù)只能由一個(gè)進(jìn)程流向另一個(gè)進(jìn)程(其中一個(gè)讀管道,一個(gè)寫管道);如果要進(jìn)行雙工通信,需要建 立兩個(gè)管道。
***管道只能用于父子進(jìn)程或者兄弟進(jìn)程間通信。,也就是說管道只能用于具有親緣關(guān)系的進(jìn)程間通信。
除了以上局限性,管道還有其他一些不足,如管道沒有名字(匿名管道),管道的緩沖區(qū)大小是受限制的。管道所傳輸?shù)氖菬o格式的字節(jié)流。這就需要管道輸入方和輸出方事先約定好數(shù)據(jù)格式。雖然有那么多不足,但對(duì)于一些簡單的進(jìn)程間通信,管道還是完全可以勝任的。
使用管道進(jìn)行通信時(shí),兩端的進(jìn)程向管道讀寫數(shù)據(jù)是通過創(chuàng)建管道時(shí),系統(tǒng)設(shè)置的文件描述符進(jìn)行的。從本質(zhì)上說,管道也是一種文件,但它又和一般的文件有所不同,可以克服使用文件進(jìn)行通信的兩個(gè)問題,這個(gè)文件只存在內(nèi)存中。
通過管道通信的兩個(gè)進(jìn)程,一個(gè)進(jìn)程向管道寫數(shù)據(jù),另外一個(gè)從中讀數(shù)據(jù)。寫入的數(shù)據(jù)每次都添加到管道緩沖區(qū)的末尾,讀數(shù)據(jù)的時(shí)候都是從緩沖區(qū)的頭部讀出數(shù)據(jù)的。
#include
int pipe(int pipefd[2]);
(匿名)管道兩端分別用描述符pipefd[0]及pipefd[1]來描述。需要注意的是,管道兩端的任務(wù)是固定的,一端只能用于讀,有描述符pipefd[0]表示,稱其為管道讀端;另一端只能用于寫,由描述符pipe[1]來表示,稱其為管道寫端。該函數(shù)創(chuàng)建的管道的兩端處于一個(gè)進(jìn)程中間,在實(shí)際應(yīng)用中沒有太大意義,因此,一個(gè)進(jìn)程在由pipe()創(chuàng)建管道后,一般再fork一個(gè)子進(jìn)程,然后通過管道實(shí)現(xiàn)父子進(jìn)程間的通信。在此不再作多介紹,下面看看有名管道吧。
管道的一個(gè)不足之處就是沒有名字,因此,只能用于具有親緣關(guān)系的進(jìn)程間通信,在有名管道(name pipe或FIFO)提出后,該限制得到了解決。FIFO不同與管道之處在與她提供一個(gè)路徑名與之關(guān)聯(lián),以FIFO的文件形式存儲(chǔ)在文件系統(tǒng)中。有名管道是一個(gè)設(shè)備文件,因此,即使進(jìn)程與創(chuàng)建FIFO的進(jìn)程不存在親緣關(guān)系,只要可以訪問該路徑,就能夠通過FIFO相互通信了。值得注意的是FIFO(First In First Out)總是按照先進(jìn)先出的原則工作,第一個(gè)被寫入的數(shù)據(jù)首先從管道中讀出。
在Linux中我們經(jīng)常使用管道重定向數(shù)據(jù)。比如:

下面介紹一下創(chuàng)建有名管道的系統(tǒng)調(diào)用,有兩個(gè),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)建有名管道的模式,指明其存取權(quán)限;dev為設(shè)備值,該值取決于文件創(chuàng)建的種類,它只在創(chuàng)建設(shè)備文件是才會(huì)用到。這兩個(gè)函數(shù)調(diào)用成功都返回0,否則返回-1.
讀寫有名管道:
#include?
ssize_t?read?(int?fd?,?void?*?buf?,?size_t?nbytes)
ssize_t?write?(int?fd?,?void?*?buf?,?size_t?nbytes)
接下來給大家演示一下通過有名管道通信的聊天程序。。。
點(diǎn)擊(此處)折疊或打開
//李四.c
#include
#include
#include
#include
#include
#include
#include
#include
#define FIFO_READ"writefifo"http://另外一個(gè)程序只要把本程序
#define FIFO_WRITE"readfifo"http://拷貝一份然后調(diào)換這兩個(gè)宏即可
#define BUF_SIZE????1024
intleft=0;
void*read_buf()
{
intrfd=-1;
char buf[BUF_SIZE]={'\0'};
inti;
printf("等待對(duì)方……\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對(duì)方已經(jīng)走開!\n");
left=1;
break;
//exit(0);
}
for(i=0;i
printf("\b");
printf("對(duì)方:%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));//通知對(duì)方
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;
}
學(xué)以置用,呵呵,效果如下:

注:本博客的文章除注明有“轉(zhuǎn)載”字樣的外,均為原創(chuàng),歡迎轉(zhuǎn)載,請(qǐng)注明文字出處,謝謝!