先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题
一 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
#include "sys/types.h"
int main(int argc, char *argv[])
{
int ret;
ret = mkfifo("./myfifo", 0777);
if (ret < 0) {
printf("create myfifo fail\n");
return -1;
}
printf("create myfifo sucess\n");
return 0;
}
编译并运行上面的程序代码,会发现在当前目录下生成一个有名管道文件myfifo
3.3 利用有名管道进行相互将通信
我们知道了如何创建有名管道之后,就可以利用有名管道实现两个任意进程间通信了,如下
(a)进程A代码
/* 先在进程A中创建一个有名管道3rd_fifo,权限是0777
* 然后以写方式打开这个有名管道文件,并向其中写入一个值
* 在另外一个进程中以只读方式打开这个有名管道文件,并读取这个值
*/
#include "stdio.h"
#include "stdlib.h"
#include
#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 fail\n");
return -1;
}
printf("create named pipe sucess\n");
}
/* 打开有名管道,以写方式打开 */
fd=open("./3rd_fifo", O_WRONLY);
if (fd < 0) {
printf("open 3rd_fifo fail\n");
return -1;
}
printf("open 3rd_fifo sucess\n");
for (i = 0; i < 5; i++) {
printf("this is first process i=%d\n", 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
#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 fail\n");
return -1;
}
printf("open 3rd_fifo sucess\n");
read(fd, &p_flag, sizeof(p_flag));
while(!p_flag);
for (i = 0; i < 5; i++) {
printf("this is second process i=%d\n", i);
usleep(100);
}
while(1);
return 0;
}
分别编译并运行
gcc 3nd_named_pipe.c -o Aprocess
gcc 3nd_named_pipe_2.c -o Bprocess
./Aprocess
./Bprocess
说明: 因为我们是在A进程中先创建的有名管道,然后在B进程中在打开这个有名管道,所以我们需要先运行A进程,然后在运行B进程;保证有名管道先被创建成功
运行结果,我们发现等A进程运行结束(打印都完成之后),B进程才会运行