Linux:命名管道(进程间通信六)

我们学习了匿名管道,我们知道匿名管道只能适用于血缘关系间的通信(比如父子),但是我们想要在两个毫不相关的进程间通信,又该怎么办呢??于是我们的命名管道,开始表演他的独门绝技--打开同一路径下的同名文件(命名管道文件) 实现通信

1.命名管道初始

我先提一个问题,进程 A 和 B 都打开 a/b/c.txt,内核中,操作系统会不会加载两次a/b/c.txt,答案是不会

因为这也太浪费资源了,我们前面学过,假如A打开了一个.txt,那么就会创建出对应的struct_file,此时struct_file指向打开的文件,如果我们再用进程B打开这个文件,虽然B也会创建一个struct_file,但是也是指向打卡文件

也就是说,A,B指向的东西是一样的,这部就满足了让两个进程看到同一份内存资源这个通信前提吗!!但是我们只想要打开该文件进行写入读取,实现通信,并不想将这个文件刷新回磁盘,所以我们有了管道文件fifo

所以我们知道,FIFO 管道文件:本质是 "伪文件"------ 它在文件系统中只有路径(用于进程定位),但所有读写操作仅在 "内核缓冲区" 中完成,数据永不刷盘

为了区别匿名管道,我们将这种管道叫做命名管道

2.用命令行mkfifo创建命名管道并进行通信

linux命令行支持用mkfifo直接创建命名管道文件

1.使用mkfifo [NAME]创建一个fifo文件,可以发现开头是p,就说明创建的是管道文件

2.使用echo来表示一个进程,linux下一切操作都是进程,echo可以理解为进程A向管道进行写入操作

可是你会发现,为什么堵塞了呢?那是因为命名管道(FIFO)的通信需要读端和写端同时存在------ 默认情况下,FIFO 的读写操作是 "阻塞模式":

  • 当你执行 echo "你好" > fifo 时,这是一个写操作,会尝试向 FIFO 写入数据
  • 但此时没有任何进程打开这个fifo作为读端 ,写操作会被内核阻塞,直到有另一个进程以 "读模式" 打开fifo,写操作才能完成

3.打开另一个终端,并且进入当前目录下,执行cat < fifo操作,模拟进程B读取fifo数据

成功进行了两个不同进程间的通信

3.使用系统函数实现两个进程通信

server.cc:

cpp 复制代码
#include <iostream>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include "common.hpp"
#include <fcntl.h>
#include <unistd.h>

int main()
{
    umask(0);
    int n = mkfifo(FIFO_FILE, 0666);
    if (n != 0)
    {
        std::cerr << "mkfifo error" << std::endl;
        return 1;
    }
    int fd = open(FIFO_FILE, O_RDONLY);
    if (fd == -1)
    {
        std::cerr << "open fifo error" << std::endl;
        return 2;
    }
    char buffer[1024];
    while (true)
    {
        n = read(fd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << "client say : " << buffer << std::endl;
        }
    }
    close(fd);
    return 0;
}

client.cc

cpp 复制代码
#include <iostream>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include "common.hpp"
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd = open(FIFO_FILE, O_WRONLY);
    if (fd == -1)
    {
        std::cerr << "open fifo error" << std::endl;
        return 2;
    }
    std::string buffer;
    while (true)
    {
        std::cout << "client : ";
        std::getline(std::cin, buffer);
        write(fd, buffer.c_str(), sizeof(buffer));
    }
    close(fd);
    return 0;
}

common.cc

cpp 复制代码
#pragma once
#define FIFO_FILE "fifo"

Makefile:

cpp 复制代码
.PHONEY : all
all : client server
client : client.cc
	g++ client.cc -o client
server : server.cc
	g++ server.cc -o server

.PHONEY : clean
clean : 
	rm -f client server fifo

我们需要先使用./server来创建管道,不然直接使用./client会因为没有创建管道而报错哦

下面是运行结果:

成功实现两个不相干进程中的通信

这就是命名管道的基本知识啦,下篇博客我们讲深入理解命名管道哦,敬请期待~~

相关推荐
春日见1 分钟前
控制算法:PP(纯跟踪)算法
linux·人工智能·驱动开发·算法·机器学习
智者知已应修善业5 分钟前
【编写函数求表达式的值】2024-4-3
c语言·c++·经验分享·笔记·算法
田里的水稻12 分钟前
C++_python_相互之间的包含调用方法
c++·chrome·python
HABuo25 分钟前
【Linux进程(四)】进程切换&环境变量深入剖析
linux·运维·服务器·c语言·c++·ubuntu·centos
工口发动机33 分钟前
ABC440DEF简要题解
c++·算法
oMcLin40 分钟前
如何在 Rocky Linux 8.7 上通过 Prometheus 与 Grafana 结合,提升大规模容器环境的监控与性能分析?
linux·grafana·prometheus
带土140 分钟前
4. C++ static关键字
开发语言·c++
橘颂TA40 分钟前
【Linux】死锁四条件的底层逻辑:从锁冲突到 STL 组件的线程安全实践(Ⅵ)
linux·运维·服务器·c++·死锁
埃伊蟹黄面43 分钟前
ELF深入解剖:从文件头到动态段,图解库的二进制构成
linux·c·
C++ 老炮儿的技术栈1 小时前
什么是通信规约
开发语言·数据结构·c++·windows·算法·安全·链表