这里写自定义目录标题
- 基本概念
- 管道特征
- 编写模型
- 有名管道模型
- 示例demo
- write.c
- read.c
- 结果
- 无名管道
基本概念
进程间存在天然的壁垒,进程间通信(Interperocess Communication,IPC)是指二个或者多个进程之间进行数据交换的过程
管道特征
管道是进程间通讯的一种常用方法。管道分为有名管道fifo和无名管道pipe
- 管道创建后是单向的,一端是写,一端是读(如果需要想双向,没办法创建二根管道)
- 管道有大小,linux内核对每个管道的大小限制在4096字节
- 无名管道一般用在父子线程间通讯
- 有名管道一般用在进程和不同线程之间通讯
- 管道是阻塞的,读取管道过程中一直处于阻塞的状态
- 管道在被读取前,只能写入一次,多次写入是无效的
编写模型
有名管道模型
步骤 | 进程A | 进程B | 步骤 |
---|---|---|---|
1.创建管道 | mkfifo | ||
2.打开管道 | open | open | 1.打开管道 |
3.读写管道 | write/read | write/read | 2.读写管道 |
4.关闭管道 | close | close | 3.关闭管道 |
5.删除管道 | unlink |
示例demo
注意:有名管道需要依靠文件来传递,我们再/tmp目录下去建文件,因为tmp目录是临时目录,开机就清除了
write.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#define FIFO_FILE "/tmp/fifo"
int main(void){
printf("创建管道...\n");
if(mkfifo(FIFO_FILE,0666) == -1){
perror("mkfifo");
return -1;
}
printf("打开管道...\n");
int fd = open(FIFO_FILE,O_WRONLY);
if(fd == -1){
perror("open");
return -1;
}
printf("发送数据...\n");
for(;;){
printf(">");
char buf[1024];
gets(buf);
if(!strcmp(buf,"!"))
break;
if(write(fd,buf,(strlen(buf)+1))) * sizeof(buf[0]) == -1){
perror("write");
return -1;
}
}
printf("关闭管道...\n");
if(close(fd) == -1){
perror("close");
return -1;
}
printf("删除管道...\n");
if(unlink(FIFO_FILE) == -1){
perror("unlink");
return -1;
}
printf("大功告成!\n");
return 0;
}
read.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define FIFO_FILE "/tmp/fifo"
int main(void){
printf("打开管道...\n");
int fd = open (FIFO_FILE,O_RDONLY);
if(fd == -1){
perror("open");
return -1;
}
printf("接收数据...\n");
for(;;){
char buf[1024];
size_t rb = read(fd,buf,sizeof(buf));
if(rb == -1){
perror("read");
return -1;
}
if(!rb)
break;
printf("< %s\n",buf);
}
printf("关闭管道...\n");
if(close(fd) == -1){
perror("close");
return -1;
}
printf("大功告成!\n");
return 0;
结果
我们先编译一下
生成write 和read二个可执行文件
我们测试一下管道
最后删除了管道,不然创建的时候会有一些莫名错误!
无名管道
这个比较简单直接上代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void){
printf("父进程:创建管道...\n");
int pipefd[2];
if(pipe(pipefd) == -1){
perror("pipe");
return -1;
}
printf("父进程:创建进程...\n");
pid_t pid = fork();
if(pid == -1){
perror("fork");
return -2;
}
/* fork之后就多了一个子进程,父进程和子进程在宏观
上是并发的关系,这样就理解为2个mian函数一起运行了
之后我们用if判断语句来做分支处理,这样实现pipe的
通讯*/
if(pid == 0){
printf("子进程:关闭写端...\n");
close(pipefd[1]);
printf("子进程:接收数据...\n");
for(;;){
char buf[1024];
ssize_t rb = read(pipefd[0],buf,sizeof(buf));
if(rb == -1){
perror("read");
return -1;
}
else if(rb == 0){
//注意:如果读到的返回结果是0,说明pipe被关闭了,这个时候结束
break;
}
puts(buf); //数据打印出来
}
printf("子进程:关闭读端...\n");
close(pipefd[0]);
printf("子进程:大功告成!\n");
}
printf("父进程:关闭读端...\n");
close(pipefd[0]);
printf("父进程:发送数据...\n");
for(;;){
char buf[1024];
if(!strcmp(buf,"!")) {
break;
}
if(write(pipefd[1],buf,strlen(buf)+1) == -1){
perror("write");
return -1;
}
}
printf("父进程:关闭写端...\n");
close(pipefd[1]);
if(wait(0) == -1){
perror("wait");
return -1;
}
printf("父进程:大功告成!\n");
return 0;
}