管道是UNIX系统IPC最古老形式,并且所有UNIX系统都提供此种通信机制。管道由下面两种局限性:
1)历史上,它们是半双工的(即数据只能在一个方向上流动)
2)它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道
管道由调用pipe函数创建:
#include <unistd.h>
int pipe(int filedes[2]);//若成功则返回0,出错返回-1
注意:filedes[0]为读而打开,filedes[1]为写而打开,filedes[1]的输出是fileds[0]的输入
单个进程中的管道几乎没有任何作用。通常,调用pipe的进程接着调用fork,这样就创建了从父进程到子进程(或反向)的IPC通道。
调用fork后做什么取决于我们想要有的数据流的方向。对于从父进程到子进程的管道,父进程关闭管道的读端(fd[0]),子进程则关闭写端(fd[1]).
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #define MAXLINE 100 //经由管道父进程向子进程传送数据 int main() { int n; int fd[2]; pid_t pid; char line[MAXLINE]; if(pipe(fd)<0) printf("pipe error"); if((pid=fork())<0) printf("fork error"); else if(pid>0) { close(fd[0]); write(fd[1],"hello world ",12); } else { close(fd[1]); n=read(fd[0],line,MAXLINE); write(STDOUT_FILENO,line,n); } exit(0); }
采用管道实现双向通信需要两个管道,控制两个不同的数据流向。现在模拟一个Client和Server双向通信的过程,Client与Server之间 可以相互发送和接收信息。此时需要两个管道进行模拟,管道1模拟Server写Client读数据流向,管道2模拟Client写Server读数据流 向。代码如下所示:
#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<errno.h> #include<string.h> int main() { int fd1[2],fd2[2]; pid_t childpid; char buf[100]; memset(buf,0,100); if(pipe(fd1)==-1) { perror("pipe()error"); exit(-1); } if(pipe(fd2)==-1) { perror("pipe() error"); exit(-1); } childpid=fork(); if(childpid==0) { printf("server input a message:"); gets(buf); close(fd1[0]); close(fd2[1]); write(fd1[1],buf,strlen(buf)); read(fd2[0],buf,100); printf("server received message from client:%s ",buf); exit(0); } if(childpid==-1) { perror("fork()error"); exit(-1); } close(fd1[1]); close(fd2[0]); read(fd1[0],buf,100); printf("client received a message from server:%s ",buf); printf("client input a message:"); gets(buf); write(fd2[1],buf,strlen(buf)); waitpid(childpid,NULL,0); return 0; }