前文中笔者介绍了管道,本文接着介绍命名管道。文中演示所用环境为 Ubuntu 18.04 desktop。

命名管道(named pipe)又被称为先进先出队列(FIFO),是一种特殊的管道,存在于文件系统中。命名管道与管道非常类似,但是又有自身的显著特征:

  • 命名管道可以用于任何两个进程间的通信,而不限于同源的两个进程。
  • 命名管道作为一种特殊的文件存放在文件系统中,而不是像管道那样存放在内核中。当进程对命名管道的使用结束后,命名管道依然存在于文件系统中,除非对其进行删除操作,否则该命名管道不会自行消失。

和管道一样,命名管道也只能用于数据的单向传输,如果要用命名管道实现两个进程间数据的双向传输,建议使用两个单向的命名管道。

创建命名管道

在命令行上创建命名管道
可以通过命令行命令 mkfifo 或 mknod 创建命名管道:

$ mkfifo /tmp/testp
$ mknod /tmp/testp p

可以通过 ls 命令查看命名管道的文件属性:

输出中的第一个字符为 p,表示这个文件的类型为管道。最后的 | 符号是有 ls 命令的 -F 选项添加的,也表示这个一个管道。

在程序中创建命名管道
在程序中创建命名管道,可以使用 mkfifo 函数,其签名如下:

#include <sys/types.h>
#include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode);

参数 pathname 是一个字符串指针,用于存放命名管道的文件路径。参数 mode 用于表示指定所创建文件的权限。该函数调用成功时返回 0;调用失败时返回 -1。
mkfifo 函数是一个专门用来创建命名管道的函数,而另外一个函数 mknod 却可以兼职创建命名文件,其函数签名如下:

#include <sys/types.h>
#include <sys/stat.h> int mknod(char *pathname, mode_t mode, dev_t dev);

创建命名管道只是 mknod 函数的功能之一,它的前两个参数和 mkfifo 函数相同。在创建命名管道时,为第三个参数 dev 传递 0 就可以了。该函数调用成功时返回 0;调用失败时返回 -1。

在程序中使用命名管道

下面的 demo 模拟一个生产者进程和消费者进程,二者通过命名管道传输数据。生产者的代码如下:

#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> #define FIFO_NAME "/tmp/testp"
#define BUFFER_SIZE 4096
#define TEN_MEG (1024 * 1024 * 10) int main(void)
{
int pipe_fd;
int res;
int open_mode = O_WRONLY;
int bytes_sent = ;
char buffer[BUFFER_SIZE + ]; if(access(FIFO_NAME, F_OK) == -)
{
res = mkfifo(FIFO_NAME, );
if(res != )
{
fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
} printf("Process %d opening FIFO O_WRONLY\n", getpid());
pipe_fd = open(FIFO_NAME, open_mode);
printf("Process %d opened fd %d\n", getpid(), pipe_fd); if(pipe_fd != -)
{
while(bytes_sent < TEN_MEG)
{
res = write(pipe_fd, buffer, BUFFER_SIZE);
if(res == -)
{
fprintf(stderr, "Write error on pipe\n");
exit(EXIT_FAILURE);
}
bytes_sent += res;
}
(void)close(pipe_fd);
}
else
{
exit(EXIT_FAILURE);
}
printf("Process %d finished\n", getpid());
exit(EXIT_SUCCESS);
}

把上面的代码保存到文件 namedpipedemo.c 中。
消费者的代码如下:

#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> #define FIFO_NAME "/tmp/testp"
#define BUFFER_SIZE 4096 int main(void)
{
int pipe_fd;
int res;
int open_mode = O_RDONLY;
int bytes_read = ;
char buffer[BUFFER_SIZE + ]; memset(buffer, '\0', sizeof(buffer)); printf("Process %d opening FIFO O_RDONLY\n", getpid());
pipe_fd = open(FIFO_NAME, open_mode);
printf("Process %d opened fd %d\n", getpid(), pipe_fd); if(pipe_fd != -)
{
do
{
res = read(pipe_fd, buffer, BUFFER_SIZE);
bytes_read += res;
} while (res > );
(void)close(pipe_fd);
}
else
{
exit(EXIT_FAILURE);
}
printf("Process %d finished, %d bytes read\n", getpid(), bytes_read);
exit(EXIT_SUCCESS);
}

把上面的代码保存到文件 namedpipedemo2.c 中。并分别编译这两个程序:

$ gcc -Wall namedpipedemo.c -o pipe1
$ gcc -Wall namedpipedemo2.c -o pipe2

先在一个终端中执行生产者:

然后在另一个终端中执行消费者:

结果是二者完成数据传输后都返回了:

删除命名管道

删除命名管道和删除一个普通文件没有什么区别:

$ rm /tmp/testp

这就可以了!

参考:
《Linux 程序设计》
《Linux 环境下 C 编程指南》

Linux 命名管道的更多相关文章

  1. linux命名管道通信过程

    前一个道,这节学习命名管道. 二命名管道 无名管道仅仅能用来在父子进程或兄弟进程之间进行通信,这就给没有亲缘关系的进程之间数据的交换带来了麻烦.解决问题就是本节要学习的还有一种管道通信:命名管道. 命 ...

  2. Linux学习笔记(13)-进程通信|命名管道

    匿名管道只能在具有亲属关系的进程间通信,那么如果想要在不具有亲戚关系,想在陌生人之间通信,那又该怎么办呢? 别慌,Linux身为世界上*强大的操作系统,当然提供了这种机制,那便是命名管道-- 所谓命名 ...

  3. Linux进程间通信(四):命名管道 mkfifo()、open()、read()、close()

    在前一篇文章—— Linux进程间通信 -- 使用匿名管道 中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关 ...

  4. 【LINUX/UNIX网络编程】之使用消息队列,信号量和命名管道实现的多进程服务器(多人群聊系统)

    RT,使用消息队列,信号量和命名管道实现的多人群聊系统. 本学期Linux.unix网络编程的第三个作业. 先上实验要求: 实验三  多进程服务器 [实验目的] 1.熟练掌握进程的创建与终止方法: 2 ...

  5. Linux进程间通信——使用命名管道

    在前一篇文章——Linux进程间通信——使用匿名管道中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关的的进程 ...

  6. Linux学习记录--命名管道通信

    命名管道通信 什么是命名管道 一个主要的限制是,它是匿名管道的应用还没有名字,因此,只有它可以用于进程间通信的方式与亲缘关系.在命名管道(named pipe或FIFO)提出后,该限制得到了克服.FI ...

  7. Linux环境进程间通信(一):管道及命名管道

    linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...

  8. 【linux】mkfifo 命令创建命名管道实现进程之间通信

    mkfifo 命令 mkfifo命令创建一个FIFO特殊文件,是一个命名管道(可以用来做进程之间通信的桥梁) 管道也是一种文件,一般是linux中的一个页大小,4k,管道数据一旦被读取就没了.(管道大 ...

  9. Linux中的pipe(管道)与named pipe(FIFO 命名管道)

    catalogue . pipe匿名管道 . named pipe(FIFO)有名管道 1. pipe匿名管道 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常 ...

随机推荐

  1. QT执行shell脚本或者执行linux指令

    由于我在做linux下的QT开发,有时候会用到shell脚本的辅助,但是需要QT运行shell脚本并获取执行结果,今天给大家分享下我的技巧,废话少说直接上代码: //执行shell指令或者shell脚 ...

  2. 【转载】Java程序模拟公安局人员管理系统

    编程题:公安人员的管理系统1) 学生类:a) 属性:i. 身份号—默认没有,需要手动进行输入ii. 姓名iii. 性别iv. 年龄v. 密码vi. 居住地址vii. 注册日期viii. 人员的信誉程度 ...

  3. leetcode题解:回文数

    判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解释: 从左向 ...

  4. MVC(实战一)

    一.创建MVC项目 二.界面分布 Content:是存放css文件等,暂时先不考虑. Controllers:重要, 控制层,控制界面显示和界面逻辑的,其实真正业务逻辑层,建议分层出去. Models ...

  5. combination sum && combination sum II

    1.Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), f ...

  6. SpringBootJPA实现增删改查

    一.目录展示 二.导入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifac ...

  7. 【第二章】Zabbix3.4监控SQLServer数据库和H3C交换机思科Cisco防火墙交换机教程笔记

    监控SQLServer数据库 SSMS执行相关SQL SQL模板命名规则 Zabbix客户端导入模板 添加SQLServer监控图形 SQLServer服务器关联模板 监控思科Cisco防火墙交换机 ...

  8. 一、I/O模型之BIO

    I/O模型之BIO 基本介绍 Java BIO 就是传统的 Java IO 编程,其相关的类和接口再 java.io 包下 BIO(blocking I/O):同步阻塞,服务器实现模式为一个连接一个线 ...

  9. ycsb 测试Hbase性能

    下载 github:https://github.com/brianfrankcooper/YCSB/releases/tag/0.10.0 wget https://github.com/brian ...

  10. jQuery 源码解析(二十四) DOM操作模块 包裹元素 详解

    本节说一下DOM操作模块里的包裹元素子模块,该模块可将当前匹配的元素替换指定的DOM元素,有如下方法: wrap(html)               ;在每个匹配元素的外层添加一层DOM元素   ...