【Linux进程间通信】深入探索:Linux下的命名管道与System V共享内存

news2024/10/9 18:37:08

📝个人主页🌹:Eternity._
⏩收录专栏⏪:Linux “ 登神长阶 ”
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

❀Linux进程间通信

  • 📒1. 命名管道
  • 📙2. 命名管道实现server&client通信
  • 📚3. system V共享内存
  • 📜4. 共享内存函数
  • 📝5. 共享内存实现server&client通信
  • 📖6. 总结


🔍前言:在Linux操作系统中,进程间通信(IPC)是一个至关重要的概念,它允许不同的进程之间进行数据交换和同步。随着现代操作系统的日益复杂,进程间通信的重要性也日益凸显。在众多IPC机制中,命名管道和System V共享内存无疑是两种最为常见且强大的工具

命名管道,又称为FIFO(First In First Out)管道,是一种在进程间传输数据的管道机制。与无名管道相比,命名管道具有更高的灵活性,因为它允许不相关的进程进行通信,而不仅仅是父子进程。这种特性使得命名管道在多种应用场景中都非常有用

另一方面,System V共享内存则是一种高效的内存共享机制。它允许多个进程共享同一块内存区域,从而可以方便地进行数据的读写操作。这种机制在需要高效数据交换的场景中特别有用,例如数据库系统、实时系统等

本文旨在深入探讨Linux进程间通信中的命名管道和System V共享内存。我们将从这两种机制的基本原理出发,逐步介绍它们的实现方式、应用场景以及相关的注意事项。通过本文的学习,你将能够深入理解Linux进程间通信的核心概念,并掌握命名管道和System V共享内存的使用方法


📒1. 命名管道

命名管道(Named Pipe),又称FIFO(First In First Out,先进先出)管道,是一种特殊类型的文件,存在于文件系统中。与匿名管道不同,命名管道可以在不相关的进程间进行数据传输,它提供了进程间通信(IPC)的一种机制


创建命名管道:

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

在这里插入图片描述


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

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

命名管道的打开规则

  • 如果当前打开操作是为读而打开FIFO时
  • O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
  • O_NONBLOCK enable:立刻返回成功
  • 如果当前打开操作是为写而打开FIFO时
  • O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
  • O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

📙2. 命名管道实现server&client通信

在这里插入图片描述


comm.hpp:

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

#define FILENAME ".fifo"

Makefile:

.PHONY:all
all:server client

server:server.cc
	g++ -o $@ $^ -std=c++11

client:client.cc
	g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -rf client

server:

#include "comm.hpp"

using namespace std;

bool MakeFifo()
{
    int n = mkfifo(FILENAME, 0666);
    if(n < 0)
    {
    	// 创建失败
        cerr << "errno: " << errno << ", strerrno: " << strerror(errno) << endl;
        return false;
    }

    cout << "mkfifo success ... ... read" << endl;
    return true;
}

int main()
{
Start:
	// 以读取的方式打开文件
    int rfd = open(FILENAME, O_RDONLY);
    if(rfd < 0)
    {
        cerr << "errno: " << errno << ", strerrno: " << strerror(errno) << endl;
        // 如果没有创建,则创建命名管道后重新打开
        if(MakeFifo()) goto Start;
        else
        {
            return 1;
        }

    }

    cout << "open fifo success" << endl;
    
	// To do
    char buffer[1024];
    while(true)
    {
    	// 读取
        ssize_t s = read(rfd, buffer, sizeof(buffer)-1);
        if(s > 0)
        {
            buffer[s] = 0; // 将最后一位变成'\0'
            cout << "Client say# " << buffer << endl;
        }
    }

    close(rfd);

    return 0;
}

client:

#include "comm.hpp"

using namespace std;

int main()
{
	// 以写入的方式打开文件
    int wfd = open(FILENAME, O_WRONLY);
    if(wfd < 0)
    {
        cerr << "errno: " << errno << ", strerrno: " << strerror(errno) << endl;
        return 1;
    }

    cout << "mkfifo success ... ... write" << endl;

    string msg;
    while(true)
    {
        cout << "Please Enter# ";
        // 从标准输入中读取数据
        getline(cin, msg);
		
		//写入数据
        ssize_t s = write(wfd, msg.c_str(), msg.size());
        if(s < 0)
        {
            cerr << "errno: " << errno << ", strerrno: " << strerror(errno) << endl;
            break;
        }
    }

    close(wfd);

    return 0;
}

在这里插入图片描述

命名管道实现server&client通信 代码


📚3. system V共享内存

System V共享内存的原理是由操作系统内核申请出一块物理内存空间,并将该空间的使用权移交给多个进程。这些进程通过各自的页表将这块物理内存映射到自己的进程地址空间中,从而实现对同一块内存区域的访问。这种方式避免了进程间通过内核进行数据传递的开销,提高了通信效率

共享内存示意图:
在这里插入图片描述

  • 共享内存的通信方式,不会提供同步机制,共享内存是直接裸露给所有的使用者的,一定要注意共享内存的使用安全问题
  • 共享内存是所有进程间通信,速度最快的
  • 共享内存可以提供较大的空间

📜4. 共享内存函数

ftok函数:

在这里插入图片描述

功能:用于生成唯一键值(key)的函数

参数说明:

  • pathname:指向文件路径的指针,这个文件通常是项目中的一个已知文件。这个路径需要指向一个实际存在的文件或目录,以便ftok函数能够获取其inode编号和设备号
  • proj_id:项目标识符,通常为一个字符或整数(但只使用其低8位)。它用于进一步区分同一文件路径下的不同IPC资源

shmget函数:

在这里插入图片描述

功能:在System V共享内存机制中创建一个新的共享内存段或获取一个已存在的共享内存段的系统调用

参数说明:

  • key:用于标识共享内存段的键值,通常由ftok函数生成。这个键值在系统中必须是唯一的,以确保不同进程能够访问到相同的共享内存段。
  • size:指定共享内存段的大小(以字节为单位)。这个大小通常是4096的倍数,因为System V共享内存是以页面为单位进行分配的。
  • shmflg:用于控制共享内存段的创建和访问权限的标志位。常用的标志位包括IPC_CREAT(如果共享内存段不存在则创建它)、IPC_EXCL(与IPC_CREAT一起使用时,如果共享内存段已存在则返回错误)、以及一系列的权限标志(如0666表示所有用户都有读写权限)
  • IPC_CREAT | IPC_EXCL:当这两个标志位一起使用时,系统调用将尝试创建一个新的IPC对象。如果对象已经存在,则调用失败并返回错误。这种组合通常用于确保创建的IPC对象是唯一的
  • 仅IPC_CREAT:当只使用IPC_CREAT标志位时,如果指定的IPC对象不存在,则创建一个新的对象;如果对象已经存在,则返回该对象的标识符。这种用法允许进程访问已存在的IPC对象
  • IPC_EXCL不能单独使用

返回值:成功返回一个非负整数,即该共享内存段的标识码(shmid);失败返回-1

  • shmid:应用这个共享内存的时候,我们使用shmid来进行操作共享内存
  • key:不要在应用层使用,只用来在内核中标识shm的唯一性

shmat函数:

在这里插入图片描述

功能:用于将共享内存段连接到进程的地址空间,使得进程可以通过指针来访问共享内存

参数说明:

  • shmid:由shmget函数返回的共享内存段标识符
  • shmaddr:希望连接的共享内存段在进程地址空间中的起始地址。通常设置为NULL
  • shmflg:控制连接行为的标志位。常用的标志位有0

shmdt函数:

在这里插入图片描述

功能:用于将共享内存段从进程的地址空间中分离(或断开连接)


shmctl函数:

在这里插入图片描述

功能:用于对共享内存段进行各种控制操作的接口,比如删除共享内存段、获取或设置其状态等

参数说明:

  • shmid:共享内存段的标识符,由shmget函数返回
  • cmd:控制命令,用于指定要执行的操作
  • buf:指向shmid_ds结构体的指针,用于存储或接收共享内存段的状态信息

在这里插入图片描述


📝5. 共享内存实现server&client通信

在这里插入图片描述


Makefile:

.PHONY:all
all:server client

server:server.cc
	g++ -o $@ $^ -std=c++11

client:client.cc
	g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -rf client server fifo

comm.hpp:

#pragma once

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

using namespace std;

// ftok所需指定的变量
const string pathname = "/home/pxt/109/linux/test_9_21";
const int proj_id = 0x11223344;

// 命名管道文件名
const string FileName = "fifo";

const int size = 4096;

// 获取key
key_t GetKey()
{
    key_t key = ftok(pathname.c_str(), proj_id);
    if(key < 0)
    {
        cerr << "errno: " << errno << ", strerrno: " << strerror(errno) << endl;
        exit(1);
    }

    return key;
}

// 将 key 转化为十六进制
string ToHex(int id)
{
    char buffer[1024];
    snprintf(buffer, sizeof(buffer), "0x%x", id);
    return buffer;
}

// 创建共享内存
int CreateShmHelper(key_t key, int flag)
{
    int shmid = shmget(key, size, flag);  

    if(shmid < 0)
    {
        cerr << "errno: " << errno << ", strerrno: " << strerror(errno) << endl;
        exit(1);
    }
    return shmid;
}

// 创建共享内存
int CreateShm(key_t key)
{
    return CreateShmHelper(key, IPC_CREAT|IPC_EXCL|0644);
}

// 获取共享内存
int GetShm(key_t key)
{
    return CreateShmHelper(key, IPC_CREAT);
}

// 创建命名管道
bool MakeFifo()
{
    int n = mkfifo(FileName.c_str(), 0666);
    if(n < 0)
    {
        cerr << "errno: " << errno << ", strerrno: " << strerror(errno) << endl;
        return false;
    }

    cout << "mkfifo success ... ... read" << endl;
    return true;
}

server:

#include "comm.hpp"

using namespace std;

// 定义一个类来管理共享内存
class Init
{
public:
    Init()
    {
    	// 用命名管道来起到同步的作用
        bool r = MakeFifo();
        if(!r)
        {
            return;
        }

        key_t key = GetKey();
        cout << "key: " << ToHex(key) << endl;

        int shmid = CreateShm(key);
        cout << "shmid: " << shmid << endl;

        cout << "开始将shm映射到进程的地址空间中" << endl;
        
        s = (char *)shmat(shmid, nullptr, 0);
        
        fd = open(FileName.c_str(), O_RDONLY);
    }

    ~Init()
    {
        shmdt(s);
        cout << "开始将shm从进程的地址空间中移除" << endl;
        
        shmctl(shmid, IPC_RMID, nullptr);
        cout << "开始将shm从OS中移除" << endl;
        
        close(fd);
        // unlink用来删除文件
        unlink(FileName.c_str());
    }
public:
    int shmid;
    int fd;
    char *s;
};

int main()
{
    Init init;

    while(true)
    {
        int code = 0;
        ssize_t n = read(init.fd, &code, sizeof(code));
        if(n > 0)
        {
            cout << "共享的内容: " << init.s << endl;
            sleep(1);
        }
        else if(n == 0)
        {
            break;
        }
    }

    return 0;
}

client:

#include "comm.hpp"

using namespace std;

int main()
{
    key_t key = GetKey();
    // 获取共享内存
    int shmid = GetShm(key);
    char *s = (char *)shmat(shmid, nullptr, 0);
    cout << "attach shm done" << endl;

    int fd = open(FileName.c_str(), O_WRONLY);
    if(fd < 0)
    {
        cerr << "errno: " << errno << ", strerrno: " << strerror(errno) << endl;
        return false;
    }

    char c = 'a';
    for(; c <= 'z'; c++)
    {
        s[c-'a'] = c;
        cout << "write: " << c << " done" << endl;
        sleep(1);

        int code = 1;
        write(fd, &code, sizeof(code));
    }

    shmdt(s);
    cout << "detach shm done" << endl;
    return 0;
}

在这里插入图片描述

共享内存实现server&client通信 代码


📖6. 总结

随着我们对Linux进程间通信中命名管道和System V共享内存的深入学习,不难发现,这两种机制在操作系统中扮演着举足轻重的角色。命名管道以其灵活性和易用性,成为了不同进程间进行数据交换的桥梁;而System V共享内存则以其高效性和低延迟,成为了高性能应用中的首选通信方式

在本文中,我们详细探讨了命名管道和System V共享内存的基本原理、实现方式、应用场景以及相关的注意事项。通过实例演示和代码分析,我们深入剖析了这两种机制的工作机制,并展示了它们在实际应用中的强大功能

虽然我们已经对命名管道和System V共享内存有了较为深入的了解,但操作系统中的进程间通信机制远不止于此。在未来的学习旅程中,我们还将继续探索其他IPC机制,如消息队列、信号量等,以更全面地掌握Linux进程间通信的核心技术

愿你在未来的学习之路上不断前行,取得更大的成就!

在这里插入图片描述

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

环境变量及命令行参数

目录 一、环境变量的概念和基本命令 二、环境变量的组织结构及获取环境变量的方式 &#xff08;1&#xff09;组织结构 &#xff08;2&#xff09;获取环境变量 命令行第三个参数 通过第三方变量environ获取 通过系统调用getenv获取 三、命令行参数 一、环境变量的概念和…

Go语言对接微信支付与退款全流程指南

在互联网技术日益发展的今天&#xff0c;线上支付已成为不可或缺的一部分。作为一门简洁高效的编程语言&#xff0c;Go&#xff08;又称Golang&#xff09;凭借其强大的并发处理能力和高效性能&#xff0c;在后端开发领域越来越受到开发者的青睐。本文将详细介绍如何使用Go语言…

学习干货IF=93.6!开发临床预测模型:分步指南

预测患者未来结果对临床实践至关重要&#xff0c;有助于医生做出明智决策。尽管每年发布大量预测模型&#xff0c;但许多研究存在方法学局限&#xff0c;如样本量不足和模型验证不充分&#xff0c;这削弱了模型的实际应用价值。因此&#xff0c;必须深入探讨并改进这些局限性&a…

电力央企数智化转型中的大模型构建及智能巡检机器人的应用

在全球经济数字化转型的大背景下&#xff0c;电力行业面临着多重挑战&#xff0c;包括能源结构的转型、市场竞争的加剧以及环境保护的压力。电力央企作为国家能源供应的中坚力量&#xff0c;亟需通过数智化转型提升竞争力和服务水平。 随着今年年初我国首次将“开展‘人工智能行…

第十四届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)

一.题目分析 &#xff08;1&#xff09;.题目 &#xff08;2&#xff09;.题目分析 1.PWM输出分析 模式切换时&#xff0c;占空比要不变&#xff0c; 在五秒之内就要变化成目标频率&#xff0c;同时要求频率的步进值要小于200hz 为了使步进值小于200hz,那么在五秒的时间之内…

AI绘画:人工智能颠覆艺术创作的新时代

*AI绘画的震撼与魅力* 你是否曾幻想过&#xff0c;手握画笔便能创造出前所未有的艺术作品&#xff1f;当我们谈及艺术&#xff0c;总会联想到那份独特的创意和灵感。而如今&#xff0c;随着人工智能的迅猛发展&#xff0c;AI绘画正以其独特的方式&#xff0c;颠覆着传统的艺术…

XTR115电流环电路原理研究【文献】

作者&#xff1a;昝 勇&#xff0c;罗永红&#xff0c;王沛莹 中航工业 摘要&#xff1a; 针对各种数据采集与监控中抗恶劣电磁干扰环境的需求&#xff0c;给出一种基于XTB115的低功耗两线4&#xff5e;20 mA电流环数据传输电路&#xff0c;首先讨论了XTR115的性能特点和工作原…

RabbitMQ简介及安装类

RabbitMQ概述-MQ介绍 RabbitMQ是一个开源的消息代理和队列服务器&#xff0c;它支持多种消息协议&#xff0c;并且可以轻松地与多种编程语言和框架集成。RabbitMQ是使用Erlang语言编写的&#xff0c;因此它具有高并发和高可用性的特点。以下是RabbitMQ的一些关键特性和概念 消息…

两文读懂DDD领域驱动设计,举例说明,通俗易懂【值得收藏】

最近对架构莫名的感兴趣&#xff0c;慢慢觉得架构本身是为了提供方便&#xff0c;定制规范&#xff0c;目标一致并更好的协作&#xff0c;它的变动也并不是像变形金刚一样&#xff0c;而是像幼苗一样按规律成长起来的 DDD是一种方法也是一种思想&#xff0c;大家前面个别概念看…

C++-再探构造函数(进阶)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 前言 来到类和对象最后一个章节&#xff0c;这里的难度已经极大程度的降低了 再探构造…

FFMpeg源码分析,关键结构体分析(一)

http://lazybing.github.io/blog/categories/ffmpegyuan-ma-fen-xi/ 一、下载FFmpeg的编译源码 进入网站&#xff1a;http://ffmpeg.org/download.html二、编译源码 执行下述命令&#xff1a; ./configure --prefix/usr/local/ffmpeg --enable-debug3 --enable-ffplay sudo …

22年408数据结构

第一题&#xff1a; 解析&#xff1a; 观察一下这个程序&#xff1a;我们注意到最外层的循环是从i1开始的&#xff0c;每次ii*2&#xff0c;直到i<n为止&#xff0c;假设程序总共执行k次执行&#xff0c;则有2^(k1)>n。则k1>log(2)n这里是以2为底n的对数, k>log(2)…

Oracle11g服务器linux 安装

一&#xff0e;安装前准备 1.检查硬件&#xff08;内存&#xff0c;交换分区&#xff0c;tmp分区&#xff0c;cpu信息&#xff0c;内核版本&#xff09; # grep MemTotal /proc/meminfo # grep SwapTotal /proc/meminfo # df -k /tmp&#xff08;>400M&#xff09; # grep …

汽车氛围灯行业分析:未来几年年复合增长率CAGR为7.15%

汽车氛围灯是一种起到装饰和指示作用的照明灯&#xff0c;它属于装饰类的照明灯。通常是红色、蓝色、绿色等&#xff0c;主要是为了使车厢更加绚丽&#xff0c;烘托气氛&#xff0c;营造室内情调。氛围灯能够具有以下特性&#xff1a;功能性、舒适性、设计感、豪华感、个性化、…

【C++】——继承

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;Yan. yan.                        …

深入解析MySQL事务管理:ACID特性与基本操作

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…

自动猫砂盆是养猫新型智商税吗?测评2024年热门款智能猫砂盆分享

铲屎官们只要一察觉到猫主子拉屎&#xff0c;就要马上去铲掉&#xff0c;这不仅是为了猫砂盆中其他干净的猫砂&#xff0c;更是为了防止猫屎残留发臭&#xff0c;特别是便便这种东西&#xff0c;一旦放久了就很招虫子&#xff0c;家里出现这些虫子又要大扫除消杀&#xff0c;特…

2024 年顶级智能文档处理解决方案

在当今的数字时代&#xff0c;智能文档处理(IDP) 对于提高业务效率和降低成本至关重要。IDP 可实现文档处理的自动化&#xff0c;最大限度地减少人工劳动和错误。由于有众多 IDP 解决方案可供选择&#xff0c;因此选择合适的解决方案可能具有挑战性。 本指南回顾了 10 款最…

Android Handler消息机制完全解析-同步屏障(三)

Android 消息机制Handler完全解析(一) Android 消息机制Handler完全解析(二) 前面两篇我们主要讲了Handler消息机制的一些基础&#xff0c;今天来看下消息屏障&#xff0c;通过本篇文章你将学到如下知识点 (1)什么是同步屏障 (2)为什么要有同步屏障 (3)同步屏障的原理 (4…

获取时隔半个钟的三天

摘要&#xff1a; 今天遇到需求是配送时间&#xff0c;时隔半个钟的排线&#xff01;所以需要拼接时间&#xff01;例如2024-10-08 14&#xff1a;30&#xff0c;2024-10-08 15&#xff1a;00&#xff0c;2024-10-08 15&#xff1a;30 <el-form-item label"配送时间&a…