pipe()函数详解

管道概述

管道也叫无名管道,它是UNIX系统IPC(进程间通信)的最古老形式,所有的UNIX系统都支持这种机制。

无名管道特点

1.半双工,数据在同一时刻只能在一个方向上流动
2.数据只能从管道的一端写入,从另一端读出
3.写入管道的数据遵循先入先从出的规则
4.管道所传送的数据不是无格式的,这要求管道的读出方和写入方必须约定好数据的格式,如多少字节算一个消息
5.管道不是普通的文件,不属于某个文件系统,其只存在于内存中
6.管道在内存中对应一个缓冲区,不同的系统其大小不一定相同
7.从管道读数据是一次性操作,数据一旦被读走,它就从管道中丢弃,释放空间以便写更多的数据
8.管道没有名字,只能在具有公共祖先的进程(父进程和子进程,或两个兄弟进程)之间使用
在这里插入图片描述

pipe函数

pipe()函数可用于创建一个管道,以实现进程间的通信。
pipe()函数的定义如下:

#include<unistd.h>

/* @param fd,经参数fd返回的两个文件描述符
 * fd[0]为读而打开,fd[1]为写而打开
 * fd[1]的输出是fd[0]的输入
 * @return 若成功,返回0;若出错,返回-1并设置errno
 */
int pipe(int fd[2]);

pipe函数定义中的fd参数是一个大小为2的数组类型指针。

通过pipe函数创建的这两个文件描述符fd[0]和fd[1]分别构成管道的两端,往fd[1]写入的数据可以从fd[0]读出,并且fd[1]一端只能进行写操作,fd[0]一端只能进行读操作,不能反过来使用。要实现双向数据传输,可以使用两个管道。

默认情况下,这一对文件描述符都是阻塞的。此时,如果我们用read系统调用来读取一个空的管道,则read将被阻塞,知道管道内有数据可读;如果我们用write系统调用往一个满的管道中写数据,则write也将被阻塞,直到管道内有足够的空闲空间可用(read读取数据后管道中将清楚读走的数据)。当然,用户可以将fd[0]和fd[1]设置为非阻塞的。

单个进程中的管道几乎没有任何用处。对于一个从父进程到子进程的管道,父进程关闭管道的读端fd[0],子进程关闭管道的写端fd[1],如下图所示:
在这里插入图片描述
当管道的一端关闭后,下列两条规则起作用

  1. 当读(read)一个写端已被关闭的管道时,在所有数据都被读取后,read返回0,表示文件结束。(从技术上来讲,如果管道的写端还有进程,就不会产生文件的结束。可以复制一个管道的描述符,使得有多个进程对它具有写打开文件描述符)
  2. 如果写(write)一个读端已被关闭的管道时,则产生信号SIGPIPE。如果忽略该信号或者捕捉该信号并从其处理程序返回,则write返回-1,errno设置为EPIPE

实例

创建一个从父进程到子进程的管道,并且父进程经由该管道向子进程传送数据

#include <unistd.h>

int main(void) {
	int n;
	int fd[2];
	pid_t pid;
	char line[MAXLINE];

	if (pipe(fd) < 0) {
		err_sys("pipe error");
	}
	if ((pid = fork()) < 0) {
		err_sys("fork error");
	} else if (pid > 0) {
	    /* parent */
		close(fd[0]);
		write(fd[1], "hello world\n", 12);
	} else {
		close(fd[1]);
		n = read(fd[0], line, MAXLINE);
		write(STDOUT_FILENO, line, n);
	}
	
	exit(0);
}

版权声明:本文为weixin_44471948原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。