【linux】进程间通信(命名管道 && System V)

我们在上一节知道了匿名管道的原理与它对应的情况与特征。

在这一节将会对命名管道 以及system V标准下的IPC进行一下原理的讲解,尤其是对共享内存的理解。

目录

命名管道:

先输出一个结论:

命名管道与匿名管道的情况与特征完全一致,除了匿名管道只能与有血缘关系的进程建立,而命名管道无这个需求。

原理我们来看一看:

下图是文件系统和进程管理的示意图:

如果我们的进程B也打开同一个文件。

进程 = 内核数据结构 + 代码与数据

故PCB与文件描述表每个进程有自己独立的一份是我们理解并接受的。

但是为什么struct file为什么有两份?
答:

其一:每个进程的文件描述表是独立的,故里面的指针也是不同的

其二:如果进程A以"w"方式打开,那么struct file内部一定会有一个表示flag的字段,此时进程B若是以"r"打开就肯定是独立的两份。

这个理解了我们再来探讨一下为什么struct file的指向是一样的?
答:

因为OS不会做浪费时空的事情,磁盘内文件的属性,方法,以及内核缓冲区绝大部分都是一样的,再重新搞一份是没有必要的,

这也就为我们为命名管道的理解有了切入点,也就是共同的内核缓冲区

但是命名管道与普通文件肯定是不一样的,命名管道至少不会向磁盘中写入数据,但是这个磁盘文件可以帮助我们定位,使两个进程以同一个路径找到。

我们先来看一看命令行中的命名管道。

我们先创建一个名为myfifo的命名管道,在管道内写完消息后,可以在另一端读出,echo是一个进程,cat是一个进程,这就完成了两个进程之间的通信。

另外我们也可以继续向管道内写入信息,并发现大小为0.

也可以证明这是一个特殊的文件。

那么如何在代码中进行创建呢?

这就用到了我们刚刚说到的要规定一个路径,用路径进行定位。

创建好了如何打开?使用open,如何写与读,使用write与read

我们可以看看下段这边的代码,实现了一个类,对以上的各种操作进行了封装。

cpp 复制代码
#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define CommPath "./fifopipe"
#define Read O_RDONLY
#define Write O_WRONLY
#define Creater 1
#define User 2
#define filename "fifopipe"
#define Default -1
#define Size 4096

class NamedPipe
{
private:
    bool OpenNamedPipe(int mode)
    {
        _fd = open(filename, mode);
        if (_fd > 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

public:
    NamedPipe(std::string path, int who)
        : _path(path), _who(who), _fd(Default)
    {
        if (_who == Creater)
        {
            int res = mkfifo(_path.c_str(), 0666);
            if (res != 0)
            {
                perror("mkfifo");
            }
        }
    }
    bool OpenForRead()
    {
        return OpenNamedPipe(Read);
    }
    bool OpenForWrite()
    {
        return OpenNamedPipe(Write);
    }

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

    int ReadOnNamedPipe(std::string* out)
    {
        char message[Size];
        int n = read(_fd, message, Size);
        *out = message;
        return n;
    }

    ~NamedPipe()
    {
        if (_who == Creater)
        {
            int res = unlink(_path.c_str());
            if (res != 0)
            {
                perror("unlink");
            }
        }
        close(_fd);
    }

private:
    std::string _path;
    int _fd;
    int _who;
};

此时我们再回归一下概念:进程间通信的前提是要先看到同一块内存空间。

匿名管道是通过继承,而命名管道是通过同一个路径。

System V:

共享内存:

消息队列(原理):

信号量(原理):

相关推荐
xsc-xyc13 小时前
用 Tailscale + Syncthing 实现手机、电脑与 NAS 的跨网络文件同步
linux·网络·网络安全·智能手机·电脑
Shepherd061913 小时前
【IT 运维】Apache 使用 mod_remoteip 恢复 Cloudflare 后的真实访客 IP
运维·tcp/ip·apache
IsJunJianXin13 小时前
pdd小程序 cdp 保存响应体
linux·服务器·小程序·pdd小程序·拼多多响应体解密·小程序cdp·拼多多rpc取响应体
王二端茶倒水13 小时前
智慧园区网络运营:认证、分权、运维和安全闭环
运维·物联网·架构
爱就是恒久忍耐13 小时前
现代CMake的build方式
linux·运维·服务器
三84414 小时前
重定向/管道符/通配符/转义字符/VI/VIM
运维·服务器
qq_谁赞成_谁反对14 小时前
甲方IT的成长之路--nginx实战--2604
服务器·数据库·nginx
fofantasy14 小时前
NSK LH25FL 升级至 NH25EM 技术规格指南
服务器·网络·数据库·经验分享·规格说明书
facaixxx202414 小时前
雨云服务器区域选择终极指南:地域速度、节点带宽、延迟及防御说明
服务器·云服务器·雨云服务器·云服务器区域·云服务器地域·云服务器节点
小坏蛋至尊宝14 小时前
如何优化文件传输的性能?
运维·服务器