码迷,mamicode.com
首页 > 系统相关 > 详细

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

时间:2016-04-12 07:45:20      阅读:262      评论:0      收藏:0      [点我收藏+]

标签:通信   管道   命名管道   缓冲区   

管道内部如何实现-大小,组织方式,环形队列?


一.进程间通信有多种方式,本文主要讲解对管道的理解。管道分为匿名管道和命名管道。

 (1)管道( pipe ):又称匿名管道。是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
 (2)命名管道 (named pipe或FIFO) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。


二.管道   

      1. 管道的特点:

(1)管道是半双工的,数据只能向一个方向流动;双方通信时,需要建立起两个管道;

(2)只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);

(3)单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

(4)数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。


  2.通信步骤

   2.1创建管道

技术分享

     利用pipe()函数创建管道,即在内核中开辟一块缓冲区(称为管道)用于通信。pipe函数调用成功返回0,调用失败返回-1。

     管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。其中fd[0]固定用于读管道,而fd[1]固定用于写管道,一般文件I/O的函数都可以用来操作管道(lseek除外)。管道的读写规则如下:


从管道中读取数据:

  • 如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;

  • 当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。注:(PIPE_BUF在include/linux/limits.h中定义,不同的内核版本可能会有所不同。Posix.1要求PIPE_BUF至少为512字节,red hat 7.2中为4096)。


向管道中写入数据:

  • 向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。 
    注:只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。



      2.2创建子进程 

   单独创建一个无名管道,并没有实际的意义。我们再fork一个子进程,然后通过管道实现父子进程间的通信(即两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先)。 

 

  2.3父进程关闭管道读端,子进程关闭管道写端


  3.代码验证

   3.1检验管道大小

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 int main()
  5 {
  6     int fd[2];
  7     int count=0;
  8     if(pipe(fd)<0)
  9     {
 10         perror("Fail to create pipe");
 11         exit(EXIT_FAILURE);
 12     }
 13     while(1)
 14     {
 15         write(fd[1],"a",sizeof(char));
 16         printf("count=%d.\n",++count);
 17     }
 18     return 0;
 19 }

运行结果:65536=64K


   3.2读写规则探究

     A.从管道中读取数据

    <1>写端不存在时

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 int main()
  5 {
  6     int n;
  7     int fd[2];
  8     int count=0;
  9     char buf[100]={0};
 10 
 11     if(pipe(fd)<0)
 12     {
 13         perror("Fail to create pipe");
 14         exit(EXIT_FAILURE);
 15     }
 16     close(fd[1]);
 17 
 18     if((n=read(fd[0],buf,sizeof(buf)))<0)
 19     {
 20         perror("Fail to read pipe");
 21         exit(EXIT_FAILURE);
 22     }
 23     printf("read %d bytes:%s\n",n,buf);
 24     return 0;
 25 }

运行结果:read 0 bytes:

  <2>写端存在时

   父进程向管道中写数据,子进程从管道中读取数据

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#define N 10
#define MAX 100

int child_read_pipe(int fd)
{
    char buf[N];
    int n = 0;
    while(1)
    {
        n = read(fd,buf,sizeof(buf));
        buf[n] = ‘\0‘;
        printf("Read %d bytes : %s\n",n,buf);
        if(strncmp(buf,"quit",4) == 0)
            break;
    }
    return 0;
}

int father_write_pipe(int fd)
{
    char buf[MAX] = {0};   
    while(1)
    {
        printf(">");
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1] = ‘\0‘;
        write(fd,buf,strlen(buf));
        sleep(1);
        if(strncmp(buf,"quit",4) == 0)
            break;
    }
    return 0;
}

int main()
{
    int pid;
    int fd[2];
    if(pipe(fd) < 0)
    {
        perror("Fail to pipe");
        exit(EXIT_FAILURE);
    }
    if((pid = fork()) < 0)
    {
        perror("Fail to fork");
        exit(EXIT_FAILURE);

    }
    else if(pid == 0)
    {
        close(fd[1]);
        child_read_pipe(fd[0]);

    }
    else
    {    
        close(fd[0]);
        father_write_pipe(fd[1]);
    }
    
    exit(EXIT_SUCCESS);
}





    

本文出自 “sunshine225” 博客,请务必保留此出处http://10707460.blog.51cto.com/10697460/1762775

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

标签:通信   管道   命名管道   缓冲区   

原文地址:http://10707460.blog.51cto.com/10697460/1762775

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!