命名管道实现本地通信

目录

命名管道实现通信

命名管道通信头文件

创建命名管道mkfifo

构造函数

以读方式打开命名管道

以写方式打开命名管道

读操作

写操作

析构函数

服务端

客户端

运行结果


命名管道实现通信

命名管道通信头文件

#pragma#include <iostream>
#include <cstdio>
#include <cerrno>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>#define DefaultFd -1
#define Creater 1
#define User 2
#define Read O_RDONLY
#define Write O_WRONLY
#define BaseSize 4096const std::string comm_path = "./myfifo";class NamePiped
{
private:bool OpenNamePipe(int mode){_fd = open(_fifo_path.c_str(), mode);if (_fd < 0)return false;return true;}public:NamePiped(const std::string &path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id == Creater){int res = mkfifo(path.c_str(), 0666);if (res != 0){perror("mkfifo");}std::cout << "creater creat named pipe" << std::endl;}}bool OpenForRead(){return OpenNamePipe(Read);}bool OpenForWrite(){return OpenNamePipe(Write);}int ReadNamedPipe(std::string* out){char buffer[BaseSize];int n = read(_fd, buffer,sizeof(buffer));if(n > 0){buffer[n] = 0;*out = buffer;}return n;}int WriteNamedPipe(const std::string &in){return write(_fd, in.c_str(),in.size());}~NamePiped(){if (_id == Creater){int res = unlink(_fifo_path.c_str());if (res != 0){perror("unlink");}std::cout << "creater free named pipe" << std::endl;}if (_fd != DefaultFd)close(_fd);}private:const std::string _fifo_path;int _id;int _fd;
};

我们要想实现用命名管道并将它封装成类来进行通信我们就要想好我们需要哪些基本成员,首先既然要创建命名管道我们是不是得先了解命名管道创建的调用接口?

创建命名管道mkfifo

查询我们的3号手册我们会发现它是我们C语言库帮我们封装好的一个接口,它的两个参数一个是你的路径名,另一个是你这个命名管道文件的权限。

创建成功,返回值返回0,否则返回-1错误码被设置。

由这个函数我们就知道我们得有命名管道的文件路径名,还有它的权限设置,权限设置我们可以直接传,但我们的路径就可以作为我们的成员变量。同样的创建命名管道我们希望只有创建者身份的进程能够创建它,所以我们需要需要一个id号来当身份证。到这里我们的3个成员变量的前两个就已经说明白了。

unlink就是C语言为我们提供的Linux上的系统调用,它的参数只有一个我们的文件路径名。这个函数的功能是将我们提供的文件名进行删除,文件内容是否进行删除是有条件的,即使文件名不再存在,只要还有进程通过打开的文件描述符访问该文件,文件就会继续保留在磁盘上。这是因为操作系统需要确保正在使用文件的进程能够正常访问其内容。只有当所有指向该文件的文件描述符都被关闭,且没有其他硬链接指向该文件时,文件的内容才会被真正删除,其占用的磁盘空间才会变得可用。

它的返回值也是一样的,成功就返回0,失败返回-1,错误码被设置。

命名管道的创建和删除我们了解了之后,我们就要来想它接下来的逻辑了。我们有两个进程,一个进程的身份是服务端(也就是我们的创建者),这个进程只会进行读操作。另一个进程的身份是客户端(我们的使用者),它只会进行我们的写操作。而我在之前的文章里有说过,命名管道也好匿名管道也好,都是文件的一种特殊形式,我们对文件怎么读,我们就对命名管道怎么读。所以既然一个只写,一个只读,那么我们就还需要一个文件描述符fd来进行我们的读写操作。至此3个成员变量的作用我们就都说明清楚了。

前面知识铺垫完毕,我再来跟大家将这个类的实现讲清楚。

构造函数

 NamePiped(const std::string &path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id == Creater){int res = mkfifo(path.c_str(), 0666);if (res != 0){perror("mkfifo");}std::cout << "creater creat named pipe" << std::endl;}}

我们的构造函数首先将我们的3个成员变量赋值,分别是文件名,身份,自身持有的文件描述符(我们暂设-1,因为还没打开文件),函数内部我们只对创建者进行创建命名管道的动作。

以读方式打开命名管道

创建好之后我们就要打开它了,打开它有两种方式,我们先来读打开

bool OpenNamePipe(int mode){_fd = open(_fifo_path.c_str(), mode);if (_fd < 0)return false;return true;}bool OpenForRead(){return OpenNamePipe(Read);}

从这里我们就能看到读打开跟打开普通文件没有任何区别。打开成功我们就可以讲文件描述符设置一下了。

以写方式打开命名管道

读是如此,写也一样。

bool OpenForWrite(){return OpenNamePipe(Write);}

我们可以看到两个复用的都是同一段的代码。

读操作

int ReadNamedPipe(std::string* out){char buffer[BaseSize];int n = read(_fd, buffer,sizeof(buffer));if(n > 0){buffer[n] = 0;*out = buffer;}return n;}

读取也是一样,文件我们怎么读,这里我们就怎么读,没有啥干货这里就不浪费时间了。

写操作

int WriteNamedPipe(const std::string &in){return write(_fd, in.c_str(),in.size());}

写操作更是如此。我们不难发现,在解决了命名管道这个问题之后,其它的操作就不难了。

析构函数

~NamePiped(){if (_id == Creater){int res = unlink(_fifo_path.c_str());if (res != 0){perror("mkfifo");}std::cout << "creater free named pipe" << std::endl;}if (_fd != DefaultFd)close(_fd);}

这里跟我们的构造函数相呼应,由谁创建就理应由谁来删除,最后我们再把各自的文件描述符一关,这样命名管道的空间就释放掉了。

服务端

#include "namedPipe.hpp"
// read:管理命名管道的整个生命周期
int main()
{NamePiped fifo(comm_path, Creater);//对于读端而言,如果我们打开文件,但是写还没来,我会阻塞在open调用中,知道对方打开//进程同步if (fifo.OpenForRead()){std::cout << "server open named pipe done" << std::endl;sleep(3);while (true){std::string message;int n = fifo.ReadNamedPipe(&message);if (n > 0){std::cout << "Client Say> " << message << std::endl;}else if (n == 0){std::cout << "Client quit,Server Too!" << std::endl;break;}else{std::cout << "fifo.ReadNamedPipe Error" << std::endl;break;}}}return 0;
}

服务端作为我们命名管道的创建者,它创建管道并以读方式打开,任然后一直读取数据,如果客户端关闭,那么意味着写端也关闭了,我们同样会退出循环。

客户端

#include "namedPipe.hpp"
// write
int main()
{NamePiped fifo(comm_path, User);if (fifo.OpenForWrite()){std::cout << "client open named pipe done" << std::endl;while (true){std::cout << "Please Enter> ";std::string message;std::getline(std::cin, message);fifo.WriteNamedPipe(message);}}return 0;
}

客户端作为我们的使用者,它会一直写一直写,知道我们自己手动退出。

运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/396.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring 框架之IOC容器加载重要组件

1.读取配置 如果配置了这样的Bean: 或者 或者 这些是不同定义bean的方式&#xff0c; 他们最终都会生成bean。 那Spring为了生成bean代码复用&#xff0c;使用统一的创建流程&#xff0c;所以通过多态方式读取不同的配置会有不同的读取器&#xff0c;读取完后后续创建bean的流程…

数字证书_CA_详解

目录 一、数字证书简介 二、 CA&#xff08;证书颁发机构&#xff09; (一) 证书链&#xff08;信任链&#xff09; 1. 根证书 2. 中间证书 3. 网站证书 (二) 抓包软件的证书链与信任机制 1. 抓包通信流程 2. 证书链伪造与信任验证流程 (三) 关于移动设备的CA 一、数…

Qt Creator 11.0创建ROS2 Humble工程

Qt Creator 11.0创建ROS2 Humble项目工程 安装ROSProjectManager插件创建ROS2项目在src下添加packagegit clone ROS2功能包编译运行安装ROSProjectManager插件 安装ROSProjectManager的主要流程参考官方的流程,地址(ros_qtc_plugin)。 此处采用二进制安装: sudo apt inst…

卡西欧模拟器:Windows端功能强大的计算器

引言 大家还记得初中高中时期用的计算器吗&#xff1f;今天给大家分享的就是一款windows端的卡西欧计算器。 软件介绍 大家好&#xff0c;我是逍遥小欢。 CASIO fx-9860G是一款功能强大的图形计算器&#xff0c;适用于数学、科学和工程计算。以下是其主要功能和特点的详细介…

软件工程专业的本科生应该具备哪些技能

软件工程专业的本科生需要具备扎实的技术基础、良好的开发流程认知和一定的软技能&#xff0c;以适应软件开发行业的需求。以下从技术技能、开发流程与工具、软技能、实践能力等维度整理核心技能清单&#xff0c;供参考&#xff1a; 一、核心技术技能 1. 编程语言 - 必学基础语…

微信小程序实现运动能耗计算

微信小程序实现运动能耗计算 近我做了一个挺有意思的微信小程序&#xff0c;能够实现运动能耗的计算。只需要输入性别、年龄、体重、运动时长和运动类型这些信息&#xff0c;就能算出对应的消耗热量。 具体来说&#xff0c;在小程序里&#xff0c;性别不同&#xff0c;身体基…

点评中是如何实现短信登录的

点评中是如何实现短信登录的 首先在这个项目中 我们主要还是通过session来实现的验证码登录 根据这个图片我们很清楚的知道 首先要制造一个随机的验证码以确保并且保存到redis中&#xff08;等下我会说为什么不存在session中&#xff09;接下来前端传来验证码 后端校验后 判断…

Kafka入门-集群基础环境搭建(JDK/Hadoop 部署 + 虚拟机配置 + SSH 免密+Kafka安装启动)

Kafka 简介 传统定义&#xff1a;Kafka是一个分布式的基于发布/订阅模式的消息队列&#xff0c;应用于大数据实时处理领域。 Kafka最新定义&#xff1a;Apache Kafka是一个开源分布式事件流平台&#xff0c;被数千家公司用于高性能数据管道、流分析、数据集成和关键任务应用…

从OSI到TCP/IP:网络协议的演变与作用

个人主页&#xff1a;chian-ocean 文章专栏-NET 从OSI到TCP/IP&#xff1a;网络协议的演变与作用 个人主页&#xff1a;chian-ocean文章专栏-NET 前言网络发展LANWAN 协议举个例子&#xff1a; 协议的产生背景 协议的标准化OSI模型参考OSI各个分层的作用各层次的功能简介 TCP/…

Java观察者模式深度解析:构建松耦合事件驱动系统的艺术

目录 观察者模式基础解析核心结构与实现原理Java内置观察者实现Spring框架中的高级应用典型应用场景与实战案例观察者模式变体与优化常见问题与最佳实践总结与未来展望1. 观察者模式基础解析 1.1 模式定义与核心思想 观察者模式(Observer Pattern)是一种行为型设计模式,它…

前端(vue)学习笔记(CLASS 7):vuex

vuex概述 vuex是一个vue的状态管理工具&#xff0c;状态就是数据 大白话&#xff1a;vuex是一个插件&#xff0c;可以帮我们管理vue通用的数据&#xff08;多组件共享的数据&#xff09; 场景 1、某个状态在很多个组件来使用&#xff08;个人信息&#xff09; 2、多个组件…

论文中pdf图片文件太大怎么办

文章目录 1.使用pdf文件的打印功能将文件导出2.操作3.前后文件大小对比 1.使用pdf文件的打印功能将文件导出 该方法在保证清晰度的同时&#xff0c;内存空间也能实现减少&#xff08;如果使用线上的压缩pdf工具&#xff0c;清晰度会直线下降&#xff09; 2.操作 点击文件—&…