进程间通信之:管道
8.2 管道
8.2.1 管道概述
本书在第2章中介绍"ps"的命令时提到过管道,当时指出了管道是Linux中一种很重要的通信方式,它是把一个程序的输出直接连接到另一个程序的输入,这里仍以第2章中的"ps –ef | grep ntp"为例,描述管道的通信过程,如图8.2所示。
图8.2 管道的通信过程
管道是Linux中进程间通信的一种方式。这里所说的管道主要指无名管道,它具有如下特点。
n 它只能用于具有亲缘关系的进程之间的通信(也就是父子进程或者兄弟进程之间)。
n 它是一个半双工的通信模式,具有固定的读端和写端。
n 管道也可以看成是一种特殊的文件,对于它的读写也可以使用普通的read()和write()等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内核的内存空间中。
8.2.2 管道系统调用
1.管道创建与关闭说明
管道是基于文件描述符的通信方式,当一个管道建立时,它会创建两个文件描述符fds[0]和fds[1],其中fds[0]固定用于读管道,而fd[1]固定用于写管道,如图8.3所示,这样就构成了一个半双工的通道。
图8.3 Linux中管道与文件描述符的关系
管道关闭时只需将这两个文件描述符关闭即可,可使用普通的close()函数逐个关闭各个文件描述符。
注意 | 当一个管道共享多对文件描述符时,若将其中的一对读写文件描述符都删除,则该管道就失效。 |
2.管道创建函数
创建管道可以通过调用pipe()来实现,表8.1列出了pipe()函数的语法要点。
表8.1 pipe()函数语法要点
所需头文件 | #include <unistd.h> |
函数原型 | int pipe(int fd[2]) |
函数传入值 | fd[2]:管道的两个文件描述符,之后就可以直接操作这两个文件描述符 |
函数返回值 | 成功:0 |
出错:-1 |
3.管道读写说明
用pipe()函数创建的管道两端处于一个进程中,由于管道是主要用于在不同进程间通信的,因此这在实际应用中没有太大意义。实际上,通常先是创建一个管道,再通过fork()函数创建一子进程,该子进程会继承父进程所创建的管道,这时,父子进程管道的文件描述符对应关系如图8.4所示。
此时的关系看似非常复杂,实际上却已经给不同进程之间的读写创造了很好的条件。父子进程分别拥有自己的读写通道,为了实现父子进程之间的读写,只需把无关的读端或写端的文件描述符关闭即可。例如在图8.5中将父进程的写端fd[1]和子进程的读端fd[0]关闭。此时,父子进程之间就建立起了一条"子进程写入父进程读取"的通道。
图8.4 父子进程管道的文件描述符对应关系 图8.5 关闭父进程fd[1]和子进程fd[0]
同样,也可以关闭父进程的fd[0]和子进程的fd[1],这样就可以建立一条"父进程写入子进程读取"的通道。另外,父进程还可以创建多个子进程,各个子进程都继承了相应的fd[0]和fd[1],这时,只需要关闭相应端口就可以建立其各子进程之间的通道。
想一想 | 为什么无名管道只能在具有亲缘关系的进程之间建立? |
4.管道使用实例
在本例中,首先创建管道,之后父进程使用fork()函数创建子进程,之后通过关闭父进程的读描述符和子进程的写描述符,建立起它们之间的管道通信。
/* pipe.c */
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_DATA_LEN 256
#define DELAY_TIME 1
int main()
{
pid_t pid;
int pipe_fd[2];
char buf[MAX_DATA_LEN];
const char data[] = "Pipe Test Program";
int real_read, real_write;
memset((void*)buf, 0, sizeof(buf));
/* 创建管道 */
if (pipe(pipe_fd) < 0)
{
printf("pipe create error\n");
exit(1);
}
/* 创建一子进程 */
if ((pid = fork()) == 0)
{
/* 子进程关闭写描述符,并通过使子进程暂停1s等待父进程已关闭相应的读描述符 */
close(pipe_fd[1]);
sleep(DELAY_TIME * 3);
/* 子进程读取管道内容 */
if ((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0)
{
printf("%d bytes read from the pipe is '%s'\n", real_read, buf);
}
- Windows CE 进程、线程和内存管理(11-09)
- 如何监控和保护Linux下进程安全 (07-12)
- uClinux进程调度器的实现分析(04-13)
- linux操作系统下的进程通信设计(01-24)
- Windows操作系统多核CPU内核线程管理方法(01-21)
- 一种基于嵌入式实时操作系统的微机保护装置网络通信方案(05-07)