进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。

IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、等。其中 Socket和Streams支持不同主机上的两个进程IPC。

一、管道的概念
管道是一种两个进程间进行单向通信的机制。 管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。管道又分为匿名管道和命名管道。管道有如下特质:

(1)其本质是一个伪文件(实为内核缓冲区)

(2) 由两个文件描述符引用,一个表示读端,一个表示写端。

(3) 规定数据从管道的写端流入管道,从读端流出。

匿名管道(pipe):

(1)只能进行单向通信;

(2)只适用于有血缘关系之间的进程;

(3)自带同步基质;

(4)在进行通信时面向字节流服务;

(5)生命进程随周期。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
因为管道传递数据的单向性,管道又称为半双工管道。管道的这一特点决定了器使用的局限性。
管道的局限性:

① 数据自己读不能自己写。

② 数据一旦被读走,便不在管道中存在,不可反复读取

③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。

④ 只能在有公共祖先的进程间使用管道。

pipe函数

创建管道
int pipe(int pipefd[2]); 成功:0;失败:-1,设置errno

函数调用成功返回r/w两个文件描述符。无需open,但需手动close。规定:fd[0] → r; fd[1] → w,就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。

管道创建成功以后,创建该管道的进程(父进程)同时掌握着管道的读端和写端。如何实现父子进程间通信呢?通常可以采用如下步骤:

java 管道 进程间通讯 进程通信 管道_父进程

  1. 父进程调用pipe函数创建管道,得到两个文件描述符fd[0]、fd[1]指向管道的读端和写端。
  2. 父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。
  3. 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信.

使用时应注意:
一,读管道:

  1. 管道中有数据,read返回实际读到的字节数。
  2. 管道中无数据:

(1) 管道写端被全部关闭,read返回0 (好像读到文件结尾)

(2) 写端没有全部被关闭,read阻塞等待(不久的将来可能有数据递达,此时会让出cpu)
二,写管道

  1. 管道读端全部被关闭, 进程异常终止(也可使用捕捉SIGPIPE信号,使进程不终止)
  2. 管道读端没有全部关闭:

(1) 管道已满,write阻塞。

(2) 管道未满,write将数据写入,并返回实际写入的字节数。

命名管道(FIFO)

FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存储于文件系统中。命名管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。值得注意的是,FIFO(first input first output)总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出。
命名管道是通过网络来完成进程之间的通信的,命名管道依赖于底层网络接口,其中包括有 DNS 服务,TCP/IP 协议 等等机制,但是其屏蔽了底层的网络协议细节。

命名管道的创建与读写

Linux下有两种⽅式创建命名管道。一是在Shell下交互地建立一个命名管道,一是在程序中使用系统函数建立命名管道。Shell方式下可使用mknod或mkfifo命令,下面命令使用mknod创建了一个命名管道:

mknod namedpipe

创建命名管道的系统函数有两个:mknod和mkfifo。两个函数均定义在头文件sys/stat.h,

函数原型如下

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

函数mknod参数中path为创建的命名管道的全路径名:mod为创建的命名管道的模式,指明其存取权限;dev为设备值,该值取决于文件创建的种类,它只在创建设备文件时才会用到。这两个函数调用成功都返回0,失败都返回-1.

这两个函数都能创建一个FIFO文件,注意是创建一个真实存在于文件系统中的文件,filename指定了文件名,而mode则指定了文件的读写权限。

mkfifo函数的作用是在文件系统中创建一个文件,该文件用于提供FIFO功能,即命名管道。前边讲的那些管道都没有名字,因此它们被称为匿名管道,或简称管道。对文件系统来说,匿名管道是不可见的,它的作用仅限于在父进程和子进程两个进程间进行通信。而命名管道是一个可见的文件,因此,它可以用于任何两个进程之间的通信,不管这两个进程是不是父子进程,也不管这两个进程之间有没有关系