1 管道(Pipe)

     管道是UNIX系统IPC的最古老的形式,并且所有的Unix系统都提供这种通信机制,当然也包括Linux。这样利用管道进行IPC管道具有如下限制:

1、历史原因造成管道是半双工的,数据只能单向流动。如果想双向通信,必须要创建两个管道。

2、管道通信双方必须有亲缘关系的进程之间(父子进程或者兄弟进程之间)。

2 管道的创建

#include <unistd.h>

int pipe(int pipefd[2]);

     经由pipefd参数返回两个文件描述符,pipefd[0]描述符用来读取管道中的数据,可以简称为管道的读端;pipefd[1]文件描述符用来向管道写入数据,简称为管道的写端。

    
返回的pipefd描述符都位于同一个进程中,没有任何意义。通常调用pipe的进程紧接着调用fork,这样就可以创建从父进程到子进程的管道(父进程
关闭pipefd[0],子进程关闭pipefd[1])或者从子进程到父进程的通信(父进程关闭pipefd[1],子进程关闭pipefd[0]),
用管道进行进程间通信了。

3 管道的读写

    
管道的读写是通过系统调用read和write完成的。pipefd[0]和pipefd[1]分别对应管道的读端和写端,pipefd[0]描述符用来
读取管道中的数据,pipefd[1]文件描述符用来向管道写入数据。如果向pipefd[0]写数据,或者向pipefd[1]读数据都将会得到错误。

     当管道一端关闭之后,遵循如下规则:

1、当所有的写端都关闭时,当管道中所有的数据都被读取后,read将会返回0,以指示达到了文件末尾。理论上如果还有进程没有关闭管道的写端的话,读端将不会到达文件末尾。

2、如果管道的读端已经关闭,再向管道写数据的话,将会产生SIGPIPE信号。默认SIGPIPE信号处理是结束当前进程,如果当前进程忽略SIGPIPE信号,则write函数返回-1,errno置为EPIPE。

    
系统常量PIPE_BUF定义了管道的大小。该系统常量定义在limits.h中,运行期可以通过pathconf或者fpathconf系统调用查询
PIPE_BUF的值。Linux中PIPE_BUF的值为4096,假如你在编写可移植的程序,请用PIPE_BUF这个宏,而不要用4096这个数值
(不同Unix系统上面PIPE_BUF值的大小是不一样的)。

    
对管道写入数据小于等于PIPE_BUF时,系统保证这个写入操作是原子操作,write将会一次性写入管道,并返回,当系统多个进程写管道时,将保证不
会穿插写入。如果写入数据量大于PIPE_BUF,则系统将不再保证写入操作为原子操作,当管道有空间,write就将会写入一部分数据,当所有的数据都
写入管道之后,write返回,当有多个进程同时写管道时,将会出现穿插写入的情况。

4 管道应用实例

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

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

	if(pipe(fd) < 0)
	{
		fprintf(stderr, "pipe error: %s\n", strerror(errno));
		exit(-1);
	}

	if((pid = fork()) < 0)
	{
		fprintf(stderr, "fork error: %s\n", strerror(errno));
		exit(-1);
	}
	else if(pid > 0) /* Parent */
	{
		close(fd[1]);
		n = read(fd[0], line, 1024);
		write(STDOUT_FILENO, line, n);
	}
	else /* Child */
	{
		close(fd[0]);
		write(fd[1], "Hello World\n", 12);
	}
}

通过例子我们可以看到,管道数据流向是从子进程到父进程的。父进程关闭了管道的写端,保留管道的读端,而子进程则关闭了管道的读端,而保留管道的写端。

5 管道的总结

通过上面的描述,我们可以总结一下他的特点:

1、数据单向流动。

2、没有管道命名,所以只能在有亲缘关系的进程间传递数据。

3、管道的大小为PIPE_BUF,写入数据不大于这个值则系统保证为原子操作,否则不保证为原子操作。

4、管道所传递的为无格式字节流。所以需要管道两端的进程之间事先定义好传输协议。

 

参考资料:

UNIX环境高级编程(AUPE)

Linux环境进程间通信(一)

原文