Linux多进程间通信——管道通信实现
之前分享了linux多进程间通信的两种方法,套接字和共享内存通信。今天来分享一下另外一种多进程通信方法——管道。
管道分为有名管道和无名管道。无名管道用于有亲缘关系之间的进程,即父子进程之间。有名管道允许没有亲属关系的进程间使用。管道是连接读写进程的一个共享文件,允许进程以先进先出的方式写入和读出数据,发送进程以字符流的形式吧大量数据写入管道尾部,接收进程从管道头部接收数据。管道应互斥使用,大小在定义时就固定下来了,之后不能改变。
无名管道:下面先介绍一下创建无名管道的API
int fds[2];//这里定义管道的文件描述符,其中一个用于读,一个用于写
pipe(fds);//无名管道的创建接口
创建成功之后,fds[0]就相当于管道头部,用于读,fds[1]相当于管道尾部,用于写进程写入数据。
有名管道:下面再介绍一下创建有名管道的API,有名管道的创建与共享内存、消息队列的创建过程都是差不多的,我们都要标记我们创建的I管道,依此来让两个进程能在内存中识别用于通信的管道是哪一个。
//写进程
define FIFO "myfifo"//这里的宏定义就是定义一个管道标识,表明我们创建的管道叫“myfifo”
mkfifo(FIFO, 0666);//mkfifo就是管道创建API,这里名字叫“myfifo”的FIFO管道就创建成功了
fd = open(FIFO, O_WRONLY);//以只写方式打开管道
write(fd, buf, sizeof(buf));
//读进程,前面都一样
define FIFO "myfifo"//这样两个进程就能识别了
mkfifo(FIFO, 0666);
fd = open(FIFO, O_RDONLY);
read(fd, buf, sizeof(buf));
下面我就给出使用有名管道实现的多进程通信的代码:
写进程:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#define FIFO "myfifo" //创建一个管道通信的键值
#define BUFFER_SIZE 1024
int main(int argc, char* argv[]){
char buf[BUFFER_SIZE];
int real_write;
int fd;
int rw = 1;
//FIFO是否存在,不存在则创建
if(access(FIFO, F_OK) == -1){
if(mkfifo(FIFO, 0666) < 0 && errno != EEXIST){
printf("falied");
exit(1);
}
}
if((fd = open(FIFO, O_WRONLY)) == -1){
printf("open failed\n");
exit(1);
}
do{
printf("请输入要写入管道的内容:\n");
fgets(buf, BUFFER_SIZE, stdin);
if((real_write = write(fd, buf, BUFFER_SIZE)) > 0){
printf("第%d次写入管道:%s\n",rw++, buf);
}
}
while(strlen(buf) != 0);
close(fd);
exit(0);
}
读进程:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#define FIFO "myfifo" //创建一个管道通信的键值
#define BUFFER_SIZE 1024
int main(int argc, char* agrv[]){
char buff[BUFFER_SIZE];
int real_read;
int fd;
int rc = 1;
//如果FIFO已经存在则直接往下执行,不存在则创建
if(access(FIFO, F_OK) == -1){
if(mkfifo(FIFO, 0666) < 0 && errno != EEXIST){//创建一个管道
printf("mkfifo failed\n");
exit(1);
}
}
//打开管道
if((fd = open(FIFO, O_RDONLY)) == -1){
printf("open failed\n");
exit(1);
}
while(1){
memset(buff, 0, BUFFER_SIZE);
if((real_read = read(fd, buff, BUFFER_SIZE)) > 0){
printf("第%d次读取管道:%s\n", rc++, buff);
}
}
close(fd);
exit(0);
}
读进程和写进程基本上一样的,只是在读写的一点区别。
下面展示一下效果,我在Ubuntu中编译之后运行: