当前位置: 首页 > news >正文

命名管道:简单案例实现

📟作者主页:慢热的陕西人

🌴专栏链接:Linux

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

本博客主要内容讲解了什么是命名管道,匿名管道和命名管道的区别,并且实现了一个案例来实践操作

文章目录

  • Linux命名管道
    • 1.概念
    • 2.创建一个命名管道
    • 3.匿名管道与命名管道的区别
    • 4.我们实现一个即时的输入输出
    • 5.完整代码

Linux命名管道

1.概念

  • 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信
  • 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道
  • 命名管道是一种特殊类型的文件

2.创建一个命名管道

  • 命名管道可以从命令行上创建,命令行方法是使用下面这个命令 :

    mkfifo filename

    image-20231128174723565

    见见猪跑:

    向管道写入:echo hello > fifo:我们发现程序卡住了,细节是我们查看fifo的文件的大小的时候,它却是0,因为我们知道管道是内存级文件,他的内容不会刷新到磁盘,所以我们看到的文件大小就是0,当我们cat < fifo也就是将fifo中的内容重定向输出到cat中打印出了hello

image-20231128193005159

那么上面的操作,是通过一个管道文件,让两个无关的进程实现的进程间的通信。那么我们知道进程间的通信就是要让两个进程看到同一个文件,那么这里我们是如何做到同一个文件呢?答案是路径,文件的唯一性就是由路径表示的!


那么我们到底是如何使用命名管道实现两个进程间的通信的:

①我们需要创建一个管道文件

这里我们需要用到一个系统接口mkfifo

image-20231128204130327

#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<string.h>
#include<cerrno>#include "comm.hpp"using namespace std;
int main()
{
//1.创建管道文件,我们今天只需要创建一次
int n  = mkfifo(filename.c_str(),mode);
if(n != 0) //创建失败
{cout << errno << " : "<< strerror(errno)<<  endl;return 1;
}return 0;
}

运行一下:

我们发现确实创建了文件:但是文件的权限却不是我们想要的0666,其实我们一下就能看出来原因是我们的umask不为零影响到了结果

image-20231128204311535

我们查看一个操作系统的接口:umask

image-20231128204715405

#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<string.h>
#include<cerrno>#include "comm.hpp"using namespace std;
int main()
{
//1.创建管道文件,我们今天只需要创建一次
umask(0); //只影响当前进程的umask
int n  = mkfifo(filename.c_str(),mode);
if(n != 0) //创建失败
{cout << errno << " : "<< strerror(errno)<<  endl;return 1;
}return 0;
}

运行一下看看:
image-20231128204930740

②让读写端进程分别按照自己的需求打开文件

 //1.不需要创建管道文件,我只需要打开对应的文件即可!int wfd = open(filename.c_str(), O_WRONLY);if(wfd < 0){cerr << errno << " : "<< strerror(errno)<<  endl;return 1;}//1.创建管道文件,我们今天只需要创建一次umask(0); //只影响当前进程的umaskint n  = mkfifo(filename.c_str(),mode);if(n != 0) //创建失败{cout << errno << " : "<< strerror(errno)<<  endl;return 1;}

③开始通信

//3.开始通信char buffer[NUM];while(true){buffer[0] = 0; //初始化第一个位置为\0//读文件ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);if(n > 0){//读成功了buffer[n] = 0;printf("%s\n", buffer);fflush(stdout);}else if(n == 0){//写端关闭cout << "client quit, me too" << endl;break;}else{//错误cout << errno << " : "<< strerror(errno)<<  endl;return 1;}}//2.开始通信char buffer[NUM];while(true){cout << "请输入要写入的信息#";char* msg = fgets(buffer, sizeof(buffer), stdin);assert(msg);(void)msg;buffer[strlen(buffer) - 1] = 0;//当我们写入quit的时候退出写端if(strcasecmp(buffer, "quit") == 0) break;ssize_t n = write(wfd, buffer, strlen(buffer));assert(n >= 0); (void)n;}

运行结果:

image-20231128223524668

3.匿名管道与命名管道的区别

  • 匿名管道由pipe函数创建并打开。
  • 命名管道由mkfifo函数创建,打开用open
  • FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义

4.我们实现一个即时的输入输出

就是我们输入管道的时候不用回车,而是选用输入一个字符就从管道输出:

我们要在client.cc端改变其向文件写入的方式,我们读取到字符c中,然后没输入一个字符就同步;

    while(true){system("stty raw");  // 使终端驱动处于一次一字符模式char c = getchar();system("stty cooked");// 使终端驱动回到一次一行模式 ssize_t n = write(wfd, &c, sizeof(char));assert(n >= 0); (void)n;}

运行结果:

打印结果

5.完整代码

client.cc

#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<cerrno>
#include<cassert>
#include"comm.hpp"using namespace std;
int main()
{//1.不需要创建管道文件,我只需要打开对应的文件即可!int wfd = open(filename.c_str(), O_WRONLY);if(wfd < 0){cerr << errno << " : "<< strerror(errno)<<  endl;return 1;}//2.开始通信char buffer[NUM];while(true){// cout << "请输入要写入的信息#";// char* msg = fgets(buffer, sizeof(buffer), stdin);// assert(msg);// (void)msg;// buffer[strlen(buffer) - 1] = 0;system("stty raw");  // 使终端驱动处于一次一字符模式char c = getchar();system("stty cooked");// 使终端驱动回到一次一行模式 // //当我们写入quit的时候退出写端// if(strcasecmp(buffer, "quit") == 0) break;ssize_t n = write(wfd, &c, sizeof(char));assert(n >= 0); (void)n;}return 0;
}

server.cc

#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<cerrno>#include "comm.hpp"using namespace std;
int main()
{//1.创建管道文件,我们今天只需要创建一次umask(0); //只影响当前进程的umaskint n = mkfifo(filename.c_str(),mode);if(n != 0) //创建失败{cout << errno << " : "<< strerror(errno)<<  endl;return 1;}cout << "创建文件成功!"<< endl;//2.打开文件int rfd = open(filename.c_str(), O_RDONLY);if(rfd < 0) //打开错误{cout << errno << " : "<< strerror(errno)<<  endl;return 2;}cout << "打开管道成功" << endl;//3.开始通信char buffer[NUM];while(true){buffer[0] = 0; //初始化第一个位置为\0//读文件ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);if(n > 0){//读成功了printf("%c", buffer[0]);fflush(stdout);}else if(n == 0){//写端关闭cout << "client quit, me too" << endl;break;}else{//错误cout << errno << " : "<< strerror(errno)<<  endl;return 1;}}//4.关闭文件close(rfd);unlink(filename.c_str());return 0;
}

comm.hpp

#pragma once#include <iostream>
#include <string>using namespace std;#define NUM 65535 //管道缓冲区大小string filename = "./fifo"; //文件名
mode_t mode = 0666; //打开方式

到这本篇博客的内容就到此结束了。
如果觉得本篇博客内容对你有所帮助的话,可以点赞,收藏,顺便关注一下!
如果文章内容有错误,欢迎在评论区指正

在这里插入图片描述

相关文章:

  • 家电产品扇叶零部件自动化三维检测设备高精度3D测量系统-CASAIM-IS(2ND)
  • 数字图像处理(实践篇)十三 数据增强之给图像添加噪声!
  • 大数据HCIE成神之路之数学(4)——最优化实验
  • Mysql DDL语句建表及空字符串查询出0问题
  • Pytorch中的Net.train()和 Net.eval()函数讲解
  • 第二部分 系统管理篇
  • 数据结构算法-分支定界算法
  • A*算法学习
  • Kubernetes概念
  • git stash save untracked not staged
  • Android-Jetpack--Hilt详解
  • 【活动回顾】sCrypt在2023伦敦区块链大会上的精彩表现
  • 基于谷歌Flutter的媒体资讯APP的设计与实现
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • tcpdump使用心得
  • 07.Android之多媒体问题
  • Nacos系列:Nacos的Java SDK使用
  • Promise面试题2实现异步串行执行
  • python大佬养成计划----difflib模块
  • ViewService——一种保证客户端与服务端同步的方法
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 前端面试题总结
  • 前端之React实战:创建跨平台的项目架构
  • 前嗅ForeSpider中数据浏览界面介绍
  • 如何设计一个微型分布式架构?
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • 阿里云移动端播放器高级功能介绍
  • 组复制官方翻译九、Group Replication Technical Details
  • ​低代码平台的核心价值与优势
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • (C语言)逆序输出字符串
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (二)丶RabbitMQ的六大核心
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (数据结构)顺序表的定义
  • (四)鸿鹄云架构一服务注册中心
  • (万字长文)Spring的核心知识尽揽其中
  • (原)本想说脏话,奈何已放下
  • (转)IOS中获取各种文件的目录路径的方法
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • .Net mvc总结
  • .NET Project Open Day(2011.11.13)
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .net分布式压力测试工具(Beetle.DT)
  • .NET开发不可不知、不可不用的辅助类(三)(报表导出---终结版)
  • @DataRedisTest测试redis从未如此丝滑
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • [ vulhub漏洞复现篇 ] ECShop 2.x / 3.x SQL注入/远程执行代码漏洞 xianzhi-2017-02-82239600
  • [ 蓝桥杯Web真题 ]-Markdown 文档解析