先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题。
一 what
前面一篇文章《linux进程间通信----管道篇(二)----无名管道》,我们谈到了无名管道,今天这篇文章我们来谈谈有名管道。
所谓有名管道,顾名思义,就是在内核中存在一个文件名,表明这是一个管道文件。
在此引申出一些扩展知识,linux中存在7种类型的文件,分别如下:
文件类型 文件特点
普通文件 标识符 ‘-’ ,用open方式创建
目录文件 标识符 ‘d’ ,用mkdir方式创建
链接文件 标识符 ‘l’, la -s, 又可以分为软链接,硬链接
管道文件 标识 ‘p’, 用mkfifo创建
socket文件 标识符 ‘s’
字符设备文件 标识符 ‘c’
块设备文件 标识符 ‘b’
其中有名管道文件、字符设备文件、块设备文件、套接字(socket)文件不占磁盘空间。
二 why
介绍了有名管道的基础概念之后,我们会问为什么需要有名管道?它能实现什么目的呢?
我们在前面的一篇文章中指出,无名管道只能用于父子进程,或者具有亲缘关系的进程间通信。如果是两个毫无关系的进程,相互间需要管道的方式来通信,要如何实现呢?这就是有名管道的作用,它可以实现这个目的。
三 how
3.1 如何创建有名管道
函数形式 : int mkfifo(const char * filename, mode_t mode)
功能 :创建管道文件
参数 :管道文件文件名,权限,创建的文件权限仍然和umask有关系
返回值 : 成功返回0,失败返回-1
注意:mkfifo并没有在内核中生成一个管道,只是在用户空间生成了一个有名管道文件
3.2 创建有名管道示例代码
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include "sys/types.h"
int main(int argc, char *argv[])
{
int ret;
ret = mkfifo("./myfifo", 0777);
if (ret < 0) {
printf("create myfifo failn");
return -1;
}
printf("create myfifo sucessn");
return 0;
}
编译并运行上面的程序代码,会发现在当前目录下生成一个有名管道文件myfifo
![7a4298e72ff05e0c98d73a31d2638634.png](https://i-blog.csdnimg.cn/blog_migrate/dd8687f35b53937e16f2af06c8291073.jpeg)
3.3 利用有名管道进行相互将通信
我们知道了如何创建有名管道之后,就可以利用有名管道实现两个任意进程间通信了,如下
(a)进程A代码
/* 先在进程A中创建一个有名管道3rd_fifo,权限是0777
* 然后以写方式打开这个有名管道文件,并向其中写入一个值
* 在另外一个进程中以只读方式打开这个有名管道文件,并读取这个值
*/
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include "sys/types.h"
#include "fcntl.h"
int main(int argc, char *argv[])
{
int i, ret, fd;
char p_flag = 0;
/* 创建有名管道 */
if (access("./3rd_fifo", 0) < 0) { //先判断有名管道文件是否存在,不存在需要先创建
ret = mkfifo("./3rd_fifo", 0777);
if (ret < 0) {
printf("create named pipe failn");
return -1;
}
printf("create named pipe sucessn");
}
/* 打开有名管道,以写方式打开 */
fd=open("./3rd_fifo", O_WRONLY);
if (fd < 0) {
printf("open 3rd_fifo failn");
return -1;
}
printf("open 3rd_fifo sucessn");
for (i = 0; i < 5; i++) {
printf("this is first process i=%dn", i);
usleep(100);
}
p_flag = 1;
sleep(5);
write(fd, &p_flag, sizeof(p_flag));
while(1);
return 0;
}
(b)进程B代码
/*
* 在本进程中以只读方式打开这个有名管道文件,并读取这个值
*/
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include "sys/types.h"
#include "fcntl.h"
int main(int argc, char *argv[])
{
int i;
int fd=open("./3rd_fifo", O_RDONLY);
char p_flag = 0;
if (fd < 0) {
printf("open 3rd_fifo failn");
return -1;
}
printf("open 3rd_fifo sucessn");
read(fd, &p_flag, sizeof(p_flag));
while(!p_flag);
for (i = 0; i < 5; i++) {
printf("this is second process i=%dn", i);
usleep(100);
}
while(1);
return 0;
}
分别编译并运行
gcc
运行结果,我们发现等A进程运行结束(打印都完成之后),B进程才会运行。