Chinaunix首页 | 论坛 | 博客
  • 博客访问: 683061
  • 博文数量: 516
  • 博客积分: 4119
  • 博客等级: 上校
  • 技术积分: 4288
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-30 17:29
文章分类

全部博文(516)

文章存档

2014年(4)

2013年(160)

2012年(352)

分类:

2012-11-01 11:21:02

原文地址:管道(一) 作者:graylocus

1.  进程间通信概述

一个大型的应用系统,往往需要众多进程协作,进程间通信的重要性就显而易见。在早期,UNIX系统IPC就是进程间通信方式的统称。进程间通信就是可以让多个进程可以互相访问,包括程序运行的实时数据,也包括对方的代码段。

2.  进程间通信的难点

进程运行期间,其地址空间对于其他进程是不可见的(这是传统上的进程概念,IPC共享内存机制打破了这个概念),在系统中他们是相对独立的,并不能互相访问对方。

Linux/UNIX系统提供了一种中间转发的机制,为多个进程建立起互相通信的数据通道。

两个进程通过IPC机制来转发数据。

3.  IPC的多种方式

IPC是进程间通信的统称,包括以下类型:

半双工通道:匿名半双工通道 + FIFO(命名半双工管道) 

全双工通道:匿名全双工 + 命名全双工

System V IPC/ POSIX IPC:消息队列 信号量 共享存储

网络进程间通信:SOCKET STREAMS

4.  管道

管道,是在两个进程之间实现一个数据流通的管道,该管道可以是单向或双向的。优点是简单易用,缺点是功能简单,有很多限制。

(1)       管道的概念

  管道实现数据以数据流的形式在多进程间流动。在系统中相当于文件系统上的一个文件,来缓存所要传输的数据。在某些特性上又不同于文件,比如,当数据读出后,管道中就没有数据了。

  匿名半双工管道在系统中是没有实名的,并不可以在文件系统中以任何方式看到该管道。它只是进程的一种资源,会随着进程的结束而被系统清除。管道通信的使用比较常见,比如grep命令。

#ls | grep tftp

这个命令使用的就是半双工管道,grep命令的输入是ls命令的输出。管道从数据流动方向上又分全双工管道+半双工管道。

(2)       匿名半双工管道

  匿名管道没有名字,对于管道中使用的文件描述符没有路径名,也就是或不存在任何意义上的文件。它们只是在内存中跟某一个索引节点相关联的两个文件描述符。

 匿名半双工管道的特性如下:

 数据只能在一个方向上流动。

 只能在具有公共祖先的进程间通信,即或是父子进程或是兄弟进程间通信

Linux环境下使用pipe函数创建一个半双工管道

#include
int pipe(int fd[2]);

参数fd[2]是一个长度为2的文件描述符数组,fd[0]是读出端,fd[1]是写入端;函数的返回值为0表示成功,-1表示失败。当函数成功返回时,自动维护了一个从fd[1]àfd[0]的数据通道。

示例:

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>

  4. int main(void)
  5. {
  6.     int fd[2];
  7.     char str[256];
  8.     
  9.     if((pipe(fd))<0){
  10.         perror("pipe");
  11.         exit(1);
  12.     }
  13.     
  14.     write(fd[1],"create pipe successfully !\n",31);
  15.     
  16.     read(fd[0],str,sizeof(str));
  17.     printf("%s",str);
  18.     
  19.     printf("pipe file descriptors are %d,%d\n",fd[0],fd[1]);
  20.     
  21.     close(fd[0]);
  22.     close(fd[1]);
  23.     
  24.     return 0;

  25. }

(3)       匿名半双工通道的读写操作

  使用readwrite函数对管道进行读写操作。当对一个读端已经关闭的管道进行写操作时,会产生SIGPIPE,说明管道的读端已经关闭,并且write操作返回-1errno的值为EPIPE,对于SIGPIPE信号可以进行捕捉处理。如果写入进程不能捕捉或者忽略SIGPIPE信号,则写入进程会中断。

 如果要建立一个父进程到子进程的数据通道,可以先调用pipe函数紧接着调用fork函数,由于子进程自动继承父进程的数据段,则父子进程同时拥有管道的操作权,此时管道的方向取决于用户怎么维护管道。

当用户想要一个父进程到子进程的数据通道时,可以在父进程中关闭管道的读出端,在子进程中关闭管道的输入端;相反,当维护子进程到父进程的数据通道时,在父进程中关闭输出,在子进程中关闭读入。使用pipe()和fork()组合,可以构造出所有的父进程与子进程或子进程到兄弟进程的管道。

示例1:父子进程间

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <fcntl.h>
  4. #include <sys/types.h>

  5. #define BUFS PIPE_BUF //PIPE_BUF,管道默认一次性读写的数据长度

  6. int main(void)
  7. {
  8.     int fd[2];
  9.     char str[256];
  10.     pid_t pid;
  11.     int len;
  12.     
  13.         
  14.     if((pipe(fd))<0){
  15.         perror("pipe");
  16.         exit(1);
  17.     }
  18.     
  19.     if((pid=fork())<0)
  20.     {
  21.         perror("failed to create pipe\n");
  22.         exit(1);
  23.     }else if((pid=fork())>0)
  24.     { //parent process
  25.         close(fd[0]);
  26.         write(fd[1],"hello pipe\n",13);
  27.         exit(0);
  28.     }else{//child process
  29.         close(fd[1]);
  30.         len = read(fd[0],buf,BUFS);
  31.     
  32.         if(len<0)
  33.         {
  34.             perror("read pipe fail\n");
  35.             exit(0);
  36.         }
  37.         else
  38.             write(STDOUT_FILENO,buf,len);//将管道中的输出到标准输出
  39.         
  40.         exit(0);
  41.     }
  42.     

  43. }


示例2:兄弟进程间

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <fcntl.h>
  4. #include <sys/types.h>

  5. #define BUFS PIPE_BUF //PIPE_BUF管道默认一次性读写的数据长度

  6. int main(void)
  7. {
  8.     int fd[2];
  9.     char str[256];
  10.     pid_t pid;
  11.     int len;
  12.     
  13.         
  14.     if((pipe(fd))<0){
  15.         perror("pipe");
  16.         exit(1);
  17.     }
  18.     
  19.     if((pid=fork())<0)
  20.     {
  21.         perror("failed to create pipe\n");
  22.         exit(1);
  23.     }else if((pid=fork())==0)
  24.     {
  25.         close(fd[0]);
  26.         write(fd[1],"hello my brother\n");
  27.         exit(0);
  28.     }
  29.     
  30.     if((pid=fork())<0)
  31.     {
  32.         perror("failed to create pipe\n");
  33.         exit(1);
  34.     }else
  35.      if((pid=fork())>0)
  36.     { //parent close fd[0],fd[1],放弃管道操作权,不对管道进行任何操作。
  37.         close(fd[0]);
  38.         close(fd[1]);
  39.         exit(0);
  40.     }else
  41.     {//brother process
  42.         close(fd[1]);//放弃写操作权
  43.         len = read(fd[0],buf,BUFS);
  44.     
  45.         if(len<0)
  46.         {
  47.             perror("read pipe fail\n");
  48.             exit(0);
  49.         }
  50.         else
  51.             write(STDOUT_FILENO,buf,len);//将管道中的输出到标准输出
  52.         
  53.         exit(0);
  54.     }
  55. }


阅读(212) | 评论(0) | 转发(0) |
0

上一篇:执行程序

下一篇:管道(二)--FIFO管道

给主人留下些什么吧!~~