进程间通信(1)---匿名管道与命名管道

管道是进程间通信一种基本的的一种方式,管道又分为两种,匿名管道和命名管道,先说匿名管道

匿名管道(pipe)

#include <unistd.h>
int pipe(int filedes[2]);

调用pipe时会在内核中开辟一个缓冲区,使用时fileds[0]为输出端,fileds[1]为写入端口,调用成功时返回0,失败时返回-1;

pipe的特点:

1:它只能在有血缘关系的进程间进行通信。

2:它只能进行单项通信,一个进程读,另一个只能写。

3:它是一种流式服务。

4:它的生命周期跟随进程的生命周期。

pipe在使用的时候有四种特殊情况,

1>(代码如下):

如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有

进程 从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像

读文件末一样。

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<sys/types.h>
  5 #include<string.h>
  6 int main()
  7 {
  8     int status=0;
  9     int _pipe_id[2];
 10     if(pipe(_pipe_id)<0)
 11     {
 12         perror("pipe");
 13         exit(1);
 14     }
 15     pid_t id=fork();
 16     if(id<0)
 17     {
 18         perror("fork");
 19     }
 20     else if(id==0)
 21     {
 22         close(_pipe_id[0]);
 23         char my_buf[]="hello world";
 24         int count=10;
 25         while(count--){
 26             //if(count<5)
 27         //  {
 28                 write(_pipe_id[1],my_buf,strlen(my_buf));
 29         //  }
 30             sleep(1);
 31         }
 32         close(_pipe_id[1]);
 33     }
 34     else
 35     {
 36         close(_pipe_id[1]);
 37         char my_buf[1024];
 38         int count=100;
 39         while(count--)
 40         {
 41             memset(my_buf,‘\0‘,sizeof(my_buf));
 42             ssize_t size= read(_pipe_id[0],my_buf,sizeof(my_buf));
 43                 printf("%d,%s\n",size,my_buf);
 44         }
 45             pid_t _wait_pid=waitpid(id,NULL,0);
 46             if(_wait_pid<0)
 47             {
 48                 return 1;
 49             }
 50     }
 51     return 0;
 52 }

输出结果就是每隔一秒读取子进程写进管道的字符串,read不停地返回零,然后结束

2>(代码将上面的代码的注释去掉)

如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写

端的 进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数

据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

3>(代码如下,将上面的父进程代码改成这样)

如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进

程向管道的写端write,那么该进程会收到信号SIGPIPE(读端关闭后,连续有两条写入的指令则会返回这个异常信号量),通常会导致进程异常终止。

 38         int count=5;
 39         while(count--)
 40         {
 41             memset(my_buf,‘\0‘,sizeof(my_buf));
 42             ssize_t size= read(_pipe_id[0],my_buf,sizeof(my_buf));
 43             printf("%d,%s\n",size,my_buf);
 44         }
 45         close(_pipe_id[0]);
 46             pid_t _wait_pid=waitpid(id,&status,0);
 47             printf("status=%d\n",status&0xff);
 48     }

输出救过如左图显示,信号量13就是SIGPIPE。

4>

如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读

端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回

子进程如下

24         int count=0;
 25         while(1){
 26             count++;
 27             ssize_t size=write(_pipe_id[1],my_buf,strlen(my_buf));
 28             if(size>0)
 29             {
 30             printf("child%d\n",count);      ;
 31             }
 32             else{
 33                 printf("child_count=%d,size=%d\n",count,size);
 34                 sleep(3);
 35             }   
 36         }   
 37     }

父进程如下

 38     else
 39     {
 40             sleep(1);
 41         close(_pipe_id[1]);
 42         char my_buf[1024];
 43         int count=15;
 44         while(count--)
 45         {
 46 
 47                 memset(my_buf,‘\0‘,sizeof(my_buf));
 48                 ssize_t size= read(_pipe_id[0],my_buf,sizeof(my_buf));
 49                 printf("%d,%s\n",size,my_buf);
 50                 sleep(5);
 51         }

在我的运行环境下(虚拟机CentOS),一次最多向管道里写入了70kb的内容,而后当父进程读取了数据才开始继续存储。


命名管道(FIFO)

因为匿名管道只能在有血缘关系的进程间通信,所以又引入了命名管道,命名管道其实就是通过建立一个公共的双方都能访问的文件来使双方进行通信,有两种方法可以建立这种管道,一个是在程序中调用mknod或mkfifo函数创建一个命名管道,另外一个方法是在shell下交互的建立一个命名管道。

#include <sys/types.h>
#include <sys/stat.h>
int mknod(const char *path,mode_t mod,dev_t dev);
int mkfifo(const char *path,mode_t mode);

函数参数第一个为路径,第二个是权限,一般使用S_IFIFO|0666来创建。

server.c

 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<string.h>
  5 #include<error.h>
  6 #include<fcntl.h>
  7 #include<unistd.h>
  8 #define _PATH_ "./.tmp_fifo"
  9 
 10 int main()
 11 {
 12     umask(0);
 13     if(mkfifo(_PATH_,0666|S_IFIFO)<0)
 14     {
 15         perror("mkfifo");
 16     }
 17     char my_buf[1024];
 18     memset(my_buf,‘\0‘,sizeof(my_buf));
 19         int fd=open(_PATH_,O_WRONLY);
 20         
 21             if(fd<0)
 22             {    
 23                     perror("open");
 24             }
 25 
 26     while(1)
 27     {
 28         printf("please write:");
 29         fflush(stdout);
 30         fgets(my_buf,sizeof(my_buf)-1,stdin);
 31         int size=write(fd,my_buf,strlen(my_buf));
 32     if(size<0)
 33     {
 34         printf("write error!\n");
 35         break;
 36     }
 37     if(strncmp(my_buf,"quit",4)==0)
 38     {
 39         break;
 40     }
 41     }
 42     close(fd);
 43     return 0;     
 44     }

client

 1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<string.h>
  5 #include<error.h>
  6 #include<fcntl.h>
  7 #include<unistd.h>
  8 
  9 #define _PATH_ "./.tmp_fifo"
 10 
 11 int main()
 12 {
 13     int fd=open(_PATH_,O_RDONLY);
 14     if(fd<0)
 15     {
 16         perror("open");
 17     }
 18     char my_buf[1024];
 19     memset(my_buf,‘\0‘,sizeof(my_buf));
 20         while(1)
 21         {
 22         int size=read(fd,my_buf,sizeof(my_buf)-1);
 23                     perror("open");
 24             }
 25 
 26     while(1)
 27     {
 28         printf("please write:");
 29         fflush(stdout);
 30         fgets(my_buf,sizeof(my_buf)-1,stdin);
 31         int size=write(fd,my_buf,strlen(my_buf));
 32     if(size<0)
 33     {
 34         printf("write error!\n");
 35         break;
 36     }
 37     if(strncmp(my_buf,"quit",4)==0)
 38     {
 39         break;
 40     }
 41     }
 42     close(fd);
 43     return 0;
 44 }

时间: 2025-01-03 17:31:26

进程间通信(1)---匿名管道与命名管道的相关文章

Linus进程间通信(一)管道、命名管道的原理及实现

进程间通信 每个进程各自有不同额用户地址空间,任何一个进程的全局变量在另一个进程中多看不到,所以进程间要交换数据必须通过内核,在内核中开辟一段缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication). 实现进程间通信的方式有:管道(pipe),命名管道(fifo),消息队列,信号量,共享内存... 管道 :是一种IPC机制,由pipe函数创建: #include <unistd.

Linux管道和命名管道

本系列序中作者概述了 linux 进程间通信的几种主要手段.其中管道和有名管道是最早的进程间通信机制之一,管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信. 认清管道和有名管道的读写规则是在程序中应用它们的关键,本文在详细讨论了管道和有名管道的通信机制的基础上,用实例对其读写规则进行了程序验证,这样做有利于增强读者对读写规则的感性认识,同时也提供了应用范例. 1 管道概述及相关API应用 1.1 管道相关的关键概

管道和命名管道

命名管道(named PIPE) 由于基于fork机制,所以管道只能用于父进程和子进程之间,或者拥有相同祖先的两个子进程之间 (有亲缘关系的进程之间).为了解决这一问题,Linux提供了FIFO方式连接进程.FIFO又叫做命名管道(named PIPE). FIFO (First in, First out)为一种特殊的文件类型,它在文件系统中有对应的路径.当一个进程以读(r)的方式打开该文件,而另一个进程以写(w)的方式打开该文件,那么内核就会在这两个进程之间建立管道,所以FIFO实际上也由内

进程间通信IPC—匿名管道(pipe)和命名管道(fifo)

管道内部如何实现-大小,组织方式,环形队列? 一.进程间通信有多种方式,本文主要讲解对管道的理解.管道分为匿名管道和命名管道. (1)管道( pipe ):又称匿名管道.是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. (2)命名管道 (named pipe或FIFO) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信. 二.管道 1. 管道的特点: (1)管道是半双工的,数据只能向一个方向流动:双方通信时,需要

进程间通信:命名管道

一.命名管道(FIFO) 匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信.如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道. 命名管道可以从命令行上创建,命令行方法是使用下面这个命令:$ mkfifo filename命名管道也可以从程序里创建,相关函数有:int mkfifo(const char *filename,mode_t mode); 二.命名管道和匿名管道 匿名管道由pipe函数创建并打开.命名管道由mkfifo

进程间通信(5) - 命名管道(FIFO)

1. 前言 本篇文章的所有例子,基于RHEL6.5平台.前一篇文章介绍了匿名管道.点此链接. 2.介绍 管道应用的一个重大限制是它没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(named pipe或FIFO)提出后,该限制得到了克服.FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中.这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,

进程间通信_03命名管道

一 为什么会有命名管道 匿名管道的产生攻克了有亲缘关系的进程之间的小量传输数据,可是匿名管道却不能在没有亲缘关系的进程之间进行传输数据. 为了解决问题,就出现了命名管道. 命名管道也是在内核分配了一块存储区,而且用一个文件名称与之关联,以FIFO(First In First Out)的文件形式存放于文件系统之中. 这样其它不相关的进程仅仅要知道管道的名称也能訪问管道. 二 和匿名管道在使用上的差别 和匿名管道的唯一差别在于管道的创建和打开方式的不同,其它操作方式全然一致. 创建的时候:命名管道

进程间通信二(命名管道)

在前一篇文章中,我们看到了如何使用匿名管道来在进程之间传递数据,这个方式有一个缺陷,就是这些进程必须由一个共同的祖先进程启动,这在不相关的的进程之间交换数据带来了不便.而另一种通信方式——命名管道,可以解决不相关进程间的通信问题. 1.什么是命名管道?命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和之前所讲的没有名字的管道(匿名管道)类似. 由于Linux中所有的事物都可被视为文件,所以对命名管道的使用也就变得与文件操作非常的统一,也使它的

c++下使用命名管道实现进程间通信

前面已经使用邮槽实现过进程间通信:http://www.cnblogs.com/jzincnblogs/p/5192654.html ,这里使用命名管道实现进程间通信. 与邮槽不同的是,命名管道在进程间传输数据是基于连接且可靠的传输方式,所以命名管道传输数据只能一对一.使用命名管道的步骤如下: ①创建命名管道,命名管道通过调用函数CreateNamedPipe()创建,函数原型如下: 1 HANDLE WINAPI CreateNamedPipe( 2 _In_ LPCTSTR lpName,