linux管道的那点事

原文地址:http://blog.chinaunix.net/uid-27034868-id-3394243.html

管道是一种两个进程间进行单向通信的机制。因为管道传递数据的单向性,管道又称为半双工管道。管道的这一特点决定了器使用的局限性。管道是Linux支持的最初Unix IPC形式之一,具有以下特点:

***数据只能由一个进程流向另一个进程(其中一个读管道,一个写管道);如果要进行双工通信,需要建 立两个管道。

***管道只能用于父子进程或者兄弟进程间通信。,也就是说管道只能用于具有亲缘关系的进程间通信。

除了以上局限性,管道还有其他一些不足,如管道没有名字(匿名管道),管道的缓冲区大小是受限制的。管道所传输的是无格式的字节流。这就需要管道输入方和输出方事先约定好数据格式。虽然有那么多不足,但对于一些简单的进程间通信,管道还是完全可以胜任的。

使用管道进行通信时,两端的进程向管道读写数据是通过创建管道时,系统设置的文件描述符进行的。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,可以克服使用文件进行通信的两个问题,这个文件只存在内存中。

通过管道通信的两个进程,一个进程向管道写数据,另外一个从中读数据。写入的数据每次都添加到管道缓冲区的末尾,读数据的时候都是从缓冲区的头部读出数据的。

#include

int pipe(int pipefd[2]);

(匿名)管道两端分别用描述符pipefd[0]及pipefd[1]来描述。需要注意的是,管道两端的任务是固定的,一端只能用于读,有描述符pipefd[0]表示,称其为管道读端;另一端只能用于写,由描述符pipe[1]来表示,称其为管道写端。该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信。在此不再作多介绍,下面看看有名管道吧。

管道的一个不足之处就是没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(name pipe或FIFO)提出后,该限制得到了解决。FIFO不同与管道之处在与她提供一个路径名与之关联,以FIFO的文件形式存储在文件系统中。有名管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信了。值得注意的是FIFO(First In First Out)总是按照先进先出的原则工作,第一个被写入的数据首先从管道中读出。

在Linux中我们经常使用管道重定向数据。比如:

下面介绍一下创建有名管道的系统调用,有两个,mknod和mkfifo

#include 

#include 

int mknod(const char *pathname, mode_t mode, dev_t dev);

int mkfifo( const char *pathname, mode_t mode );

函数mknod参数中pathname为创建有名管道的全路径名,mode为创建有名管道的模式,指明其存取权限;dev为设备值,该值取决于文件创建的种类,它只在创建设备文件是才会用到。这两个函数调用成功都返回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"//另外一个程序只要把本程序

#define FIFO_WRITE"readfifo"//拷贝一份然后调换这两个宏即可

#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;

}

学以置用,呵呵,效果如下:

注:本博客的文章除注明有“转载”字样的外,均为原创,欢迎转载,请注明文字出处,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容