进程间通信---有名管道&无名管道

顾名思义,管道就像是将数据放入到一个长长的管子中一样,肯定会有一端写入数据,称为写端,有一段读出数据,称为读端。既然是说像管子一样那么它肯定有大小吧,资源不是无穷无尽的,默认下管道的大小是64k,用ulimit -a 可以查看。

1、无名管道:

  1. 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立两个管道
  2. 无名管道只能用于父子进程之间(因为父子进程共享打开的文件描述符)
  3. 无名管道对于管道两端的进程而言就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自己单独构成一种文件系统,并且只存在在内核中。(这也是他无法在没有亲缘关系的进程中使用的原因)
  4. 数据的读出和写入:一个进程向管道的一端写数据,另一个进程在管道的另一端读。

 

无名管道的创建:

Int pipe(int pipefd[2]);当一个管道创建时,它会产生两个文件描述符fd[0]和fd[1],分别为读端和写端。现在假设fork()创建一个新进程,父进程负责向管道中写数据,子进程复制读数据。那么父进程要关闭读端,子进程要关闭写端。

规则:

  1. 写端不存在时,则认为已经读到数据的尾部,读函数返回读到的字节数为0
  2. 写端存在时,如果写的字节数大于PIPE_BUF(管道默认大小65535,64k)则返回管道现有数据,如果小于PIPE_BUF,则返回实际大小。
  3. 当写端存在,管道没有数据时,读取管道时会阻塞
  4. 当读端存在时,向管道中写数据才有意义。否则,管道写端进程会收到内核传来的SIGPIPE信号,用户程序可以处理该信号,也可以忽略(默认使应用程序终止)

 

2、有名管道

有名管道的文件形式存在于文件系统中,这样就可以是任意两个进程之间通信。FIFO文件严格遵循先进先出的规则,对文件的读总是从开始处返回数据,对文件的写则把数据加到末尾。都不支持lseek()等文件定位操作。

注意:有名管道的名字存在与文件系统中,内容存放在内存中。

 

有名管道的创建:

Int mkfifo(const char *pathname ,mode_t  mode)

第一个参数:一个路径名,也就是创建后FIFO的名字

第二个参数:权限设置

如果mkfifo的第一个参数已存在时,返回一个EEXIST错误。

有名管道比无名管道多一个打开操作:open

打开规则:

(1)如果当前为读而打开文件,若有相应进程为写打开了文件,则当前打开操作成功返回,否则会阻塞到有进程为写打开文件。

(2)如果当前为写打开文件,若有相应进程为读打开了文件,则当前打开操作成功返回,否则会阻塞到有进程为打开文件。

 

3、有名管道和无名管道的区别

其实在上面介绍两者时已经把它们的区别说了最主要的一点是:

  1. 无名管道只能在父子进程直接通信,有名管道可以在任意两个进程间通信
  2. 无名管道是进程创建管道时存在的,它不存在于文件系统中,故别的进程无法看到它所以不能和它通信。有名管道存在于文件系统中,别的进程可以看到它的文件描述符,但是它们的内容都是存在内存中而非磁盘上。

猜你喜欢

转载自blog.csdn.net/ShWe_yayaya/article/details/81739975