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

Linux操作系统--进程间通信(中)(命名管道)

目录

1.命名管道:

1.1创建一个命名管道

1.2匿名管道与命名管道的区别

1.3命名管道的打开规则

1.4例子1-用命名管道实现文件拷贝

1.5例子2-用命名管道实现server&client通信


1.命名管道:

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

1.1创建一个命名管道

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

$ mkfifo filename

  • 命名管道也可以从程序里创建,相关函数有:

int mkfifo(const char* filename, mode_t mode);

  • 创建命名管道

int main(int argc, char *argv[])

{

        mkfifo("p2",0644);

        return 0;
}

1.2匿名管道与命名管道的区别

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

1.3命名管道的打开规则

  • 如果当前打开操作是为读而打开FIFO时

O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO

O_NONBLOCK enable:立刻返回成功

  • 如果当前打开操作是为写而打开FIFO时

O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO

O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

1.4例子1-用命名管道实现文件拷贝

读取文件,写入命名管道:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#define ERR_EXIT(m) do{perror(m),exit(EXIT_FAILURE);}while(0)int main(int argc, char *argv[])
{mkfifo("tp",0644);int infd;infd = open("abc",O_RDONLY);if(infd == -1)ERR_EXIT("open");int outfd;outfd = open("tp",O_WRONLY);if(outfd == -1)ERR_EXIT("open");char buf[1024];int n;while((n=read(infd, buf, 1024))>0){write(outfd, buf, n);}close(infd);close(outfd);return 0;
}

读取管道,写入目标文件:
 

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#define ERR_EXIT(m) do{perror(m),exit(EXIT_FAILURE);}while(0)int main(int argc, char *argv[])
{int outfd;outfd = open("abc.bak",O_WRONLY|O_CREAT|O_TRUNC,0644);if(outfd == -1)ERR_EXIT("open");int infd;infd = open("tp",O_RDONLY);if(outfd == -1)ERR_EXIT("open");char buf[1024];int n;while((n=read(infd, buf, 1024))>0){write(outfd, buf, n);}close(infd);close(outfd);unlink("tp");return 0;
}

1.5例子2-用命名管道实现server&client通信

server.cc

#include "comm.hpp"
#include "log.hpp"using namespace std;// 管理管道文件
int main()
{Init init;Log log;// log.Enable(Onefile);log.Enable(Onefile);// 打开管道int fd = open(FIFO_FILE, O_RDONLY); // 等待写入方打开之后,自己才会打开文件,向后执行, open 阻塞了!if (fd < 0){log(Fatal, "error string: %s, error code: %d", strerror(errno), errno);exit(FIFO_OPEN_ERR);}log(Info, "server open file done, error string: %s, error code: %d", strerror(errno), errno);log(Warning, "server open file done, error string: %s, error code: %d", strerror(errno), errno);log(Fatal, "server open file done, error string: %s, error code: %d", strerror(errno), errno);log(Debug, "server open file done, error string: %s, error code: %d", strerror(errno), errno);// 开始通信while (true){char buffer[1024] = {0};int x = read(fd, buffer, sizeof(buffer));if (x > 0){buffer[x] = 0;cout << "client say# " << buffer << endl;}else if (x == 0){log(Debug, "client quit, me too!, error string: %s, error code: %d", strerror(errno), errno);break;}elsebreak;}close(fd);return 0;
}

client.cc

#include <iostream>
#include "comm.hpp"using namespace std;int main()
{int fd = open(FIFO_FILE, O_WRONLY);if(fd < 0){perror("open");exit(FIFO_OPEN_ERR);}cout << "client open file done" << endl;string line;while(true){cout << "Please Enter@ ";getline(cin, line);write(fd, line.c_str(), line.size());}close(fd);return 0;
}

comm.hpp

#pragma once#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>#define FIFO_FILE "./myfifo"
#define MODE 0664enum
{FIFO_CREATE_ERR = 1,FIFO_DELETE_ERR,FIFO_OPEN_ERR
};class Init
{
public:Init(){// 创建管道int n = mkfifo(FIFO_FILE, MODE);if (n == -1){perror("mkfifo");exit(FIFO_CREATE_ERR);}}~Init(){int m = unlink(FIFO_FILE);if (m == -1){perror("unlink");exit(FIFO_DELETE_ERR);}}
};

log.hpp

#pragma once#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>#define SIZE 1024#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4#define Screen 1
#define Onefile 2
#define Classfile 3#define LogFile "log.txt"class Log
{
public:Log(){printMethod = Screen;path = "./log/";}void Enable(int method){printMethod = method;}std::string levelToString(int level){switch (level){case Info:return "Info";case Debug:return "Debug";case Warning:return "Warning";case Error:return "Error";case Fatal:return "Fatal";default:return "None";}}// void logmessage(int level, const char *format, ...)// {//     time_t t = time(nullptr);//     struct tm *ctime = localtime(&t);//     char leftbuffer[SIZE];//     snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),//              ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,//              ctime->tm_hour, ctime->tm_min, ctime->tm_sec);//     // va_list s;//     // va_start(s, format);//     char rightbuffer[SIZE];//     vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);//     // va_end(s);//     // 格式:默认部分+自定义部分//     char logtxt[SIZE * 2];//     snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);//     // printf("%s", logtxt); // 暂时打印//     printLog(level, logtxt);// }void printLog(int level, const std::string &logtxt){switch (printMethod){case Screen:std::cout << logtxt << std::endl;break;case Onefile:printOneFile(LogFile, logtxt);break;case Classfile:printClassFile(level, logtxt);break;default:break;}}void printOneFile(const std::string &logname, const std::string &logtxt){std::string _logname = path + logname;int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // "log.txt"if (fd < 0)return;write(fd, logtxt.c_str(), logtxt.size());close(fd);}void printClassFile(int level, const std::string &logtxt){std::string filename = LogFile;filename += ".";filename += levelToString(level); // "log.txt.Debug/Warning/Fatal"printOneFile(filename, logtxt);}~Log(){}void operator()(int level, const char *format, ...){time_t t = time(nullptr);struct tm *ctime = localtime(&t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,ctime->tm_hour, ctime->tm_min, ctime->tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式:默认部分+自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);// printf("%s", logtxt); // 暂时打印printLog(level, logtxt);}private:int printMethod;std::string path;
};// int sum(int n, ...)
// {
//     va_list s; // char*
//     va_start(s, n);//     int sum = 0;
//     while(n)
//     {
//         sum += va_arg(s, int); // printf("hello %d, hello %s, hello %c, hello %d,", 1, "hello", 'c', 123);
//         n--;
//     }//     va_end(s); //s = NULL
//     return sum;
// }

1.6便于理解

唯一性:进程间通信的前提,先让不同进程看到同一份资源

管道文件:属于内存级文件,不需要刷盘

理解:如果两个不同的进程,打开同一个文件的时候,在内核中,操作系统会打开几个文件?(同路径同一个文件名 = 路径+文件名)

相关文章:

  • 数据库索引优化实战: 如何设计高效的数据库索引
  • 如何在纯C中实现类、继承和多态(小白友好版)
  • Go-web开发之帖子功能
  • 数值与字典解决方案第二十六讲:FILTER函数在去除数据的方法
  • 旧版本NotionNext图片失效最小改动解决思路
  • 对第三方软件开展安全测评,如何保障其安全使用?
  • AimRT从入门到精通 - 04RPC客户端和服务器
  • 【网络安全实验】SSL协议的应用
  • 【AI提示词】系统分析员
  • react + antd 实现后台管理系统
  • 计算机视觉的未来发展趋势
  • 【学习笔记】深入理解Java虚拟机学习笔记——第1章 走进Java
  • python实现基于Windows系统计算器程序
  • 复刻低成本机械臂 SO-ARM100 舵机配置篇(WSL)
  • FastAPI 与数据库交互示例
  • QGraphicsView QGraphicsScene QGraphicsItem 的关系
  • 文本中地理位置提取方法—正则和NLP模型
  • 吴恩达深度学习作业 RNN模型——字母级语言模型
  • Web 应用服务器:功能、类型与核心作用全解析
  • 写了个脚本将pdf转markdown
  • 桥,在黄岩与上海之间|劳动者的书信③
  • 叙利亚多地遭以色列空袭
  • 一周文化讲座|那些年的年青人
  • 生命与大海相连:他在300多米的深海行走,在沉船一线打捞救援
  • 马上评丨准入壁垒越少,市场活力越足
  • 深入贯彻中央八项规定精神学习教育中央指导组培训会议召开