Linux进程通信 ---匿名/命名管道 --- 共享内存(一)

简介: Linux进程通信 ---匿名/命名管道 --- 共享内存(一)

通信的概念

进程之间的数据传输,资源共享,发送通知,进程控制就属于进程间的通信

数据传输:

一个进程将其数据发送给另一个进程

资源共享:

多个进程之间共享同样的资源

通知事件:

一个进程向另一个进程发送消息也可以是向一组进程发送消息

进程控制:

一个进程控制另一个进程的执行

目前通信的主要标准分类为:

POSIX — 让通信可以跨主机

System V — 聚焦在本地通信

基于文件的通信方式为:管道

通信的本质:

因为进程具有独立性,所以通信并不是进程之间的直接交互,而是由操作系统直接或间接的给通信双方的进程提供内存空间,内存空间里的数据就是公共资源,而通信的前提就是需要通信的进程都必须看到同一份公共资源。不同的通信种类就是操作系统中不同的模板提供的。由上述即可得知,通信并不是低成本的工作。

管道

管道是基于文件系统的通信方式:从一个进程连接到另一个进程的数据流称为一个管道

每个文件都会有一个属于自己的内核缓冲区,这个区域就属于是进程之间的公共资源。因此进程间的通信就可通过这个内核缓冲区去实现。而这种基于文件系统的通信就是管道通信,这个文件就称为管道文件。管道文件时内存级的文件,不需要进行IO。一般而言管道只能用来进行单向数据通信

管道的特征:

  1. 管道的生命周期随进程,进程退出则管道释放
  2. 只要是具有血缘关系的进程就可以进行管道通信
  3. 管道是面向字节流的(网络)
  4. 单向通信
  5. 管道具有互斥与同步的机制

管道的系统调用

int pipe(int pipefd[2]); — <unistd.h>

创建匿名管道

创建失败返回-1, 创建成功返回0.

参数为输出型参数,需要将两个文件描述符(分别对应进程读和写)传入这个参数

创建成功后,数组保存两个文件描述符:pipfd[0] — 读;pipfd[1] — 写

b7b4a090b7a795538a476a380ae07c20.png


int mkfifo(const char *filename,mode_t mode); — <sys/types.h><sys/stat.h>

创建以权限p开头的命名管道文件

参数1为文件名(C类型的字符串),参数2为文件的权限

创建失败返回-1, 创建成功返回0.

4fc64b2ac5cc27a72cfc64e1c6ce1263.png

int unlink(const char* path); — <unistd.h>

删除管道文件

删除成功返回0.

be17e38cf4813cdb1ad04e062e740d23.png

匿名管道

通过父进程创建子进程去继承文件地址的方式,使得两进程看到同一个内存级文件,此时的内存级文件没有名称就称为匿名管道

创建匿名管道的步骤:

父进程创建出管道,分别以读和写的方式打开文件(为了让子进程继承,方便后期选择对于文件的单向数据通信)


05ef8e31b159caccf587c0c3578fde0c.png

父进程创建出子进程

e0e83e3e2a4cdc5d0f7854d425faa0f0.png

命名管道

父进程关闭读,子进程关闭写(根据需求可自行关闭读/写),必须一个负责读一个负责写


30ac1d2a2bca81861c12382a83202150.png

匿名管道的读写特征:

  1. 当写的速度比读的速度慢时,会导致管道中没有数据,默认会将读的进程阻塞,等待管道有数据
  2. 当读的速度比写的速度慢时,会导致管道空间写满,默认会将写的进程阻塞等待读端读取
  3. 当写关闭后,读端会将数据读完,可由用户自行设置读完后的操作
  4. 当读关闭后,写就失去了意义,操作系统会发信号终止写的进程
int main(){
    //1、创建管道文件,打开读写端
    int fds[2];
    int n = pipe(fds);
    assert(n == 0);
    //2、创建子进程
    pid_t id = fork();
    assert(id >= 0);
    //3、根据需求删除进程的读或写,确保单向传输
    //父进程读,子进程写
    if(id == 0){
        //子进程
        //子进程关闭读
        close(fds[0]);
        int count = 0;
        while(1){
            char buff[1024];
            //写入字符串
            snprintf(buff, sizeof(buff), "I am child -> parent: %d\n", ++count);
            write(fds[1], buff, strlen(buff));
            //每隔一秒写一次
            sleep(1);
        }
        exit(0);
    }
    //父进程
    //父进程关闭写
    close(fds[1]);
    //父进程读
    while(1){
        char buff[1024];
        //在管道文件中读取到父进程的buff
        ssize_t i = read(fds[0], buff, sizeof(buff) - 1);
        //将独到的字符串最后加上\0
        if(i > 0)
            buff[i] = 0;
        cout << "parent: " << buff << endl;
    }
    //等待
    n = waitpid(id, nullptr, 0);
    assert(id == n);
    return 0;
}

命名管道

创建一个以权限p开头的文件,进程可以往文件里写入也可以从文件里读取,实现通信

命名管道文件根据名称具有唯一性,进程可以通过路径 + 文件名 找到命名管道文件,从而实现通信

管道的读端在打开文件后不会继续往后运行,直至管道的写端也打开文件后才会继续运行

命名管道的通信需要两个不相干的进程来实现,如下代码示例

name_pipe.hpp

#pragma once
#include<iostream>
#include<string>
#include<cerrno>
#include<cassert>
#include<cstring>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
using namespace std;
#define NAME_PIPE "./MyPipe"//宏定义管道文件名字与路径
//创建管道文件
bool CreatFilePipe(const string& path){
    umask(0);
    int n = mkfifo(path.c_str(), 0666);
    if(n == 0)
        return true;
    else{
        std::cout << errno << " " << strerror(errno) << endl;
        return false;
    }
}
//删除管道文件
void RemoveFifo(const string& path){
    assert(unlink(path.c_str()) == 0);
}

Read.cc

#include"name_pipe.hpp"
using namespace std;
//读取
int main(){
    //创建文件
    //读端负责创建管道文件
    bool flags = CreatFilePipe(NAME_PIPE);
    assert(flags);
  //创建成功后,打开管道文件
    int fd = open(NAME_PIPE, O_RDONLY);
    if(fd < 0) exit(1);
    char buff[1024];
    while(1){
      //读取管道文件中的数据
        ssize_t s = read(fd, buff, sizeof(buff) - 1);
        //读取成功
        if(s > 0){
            buff[s] = 0;
            std::cout << "Read: " << buff << endl;
        }
        //没有读到数据
        else if(s == 0){
            std::cout << "stop" << endl;
            break;
        }
        //读取出错
        else
            break;
    }
    close(fd);
  //删除管道文件
    RemoveFifo(NAME_PIPE);
    return 0;
}

Write.cc

#include"name_pipe.hpp"
using namespace std;
//写入
int main(){
  //因为读端已经有创建除了管道文件,写端只需要打开即可
    int fd = open(NAME_PIPE, O_WRONLY);
    if(fd < 0) exit(1);
    string str;
    while(1){
      //往管道文件里写入数据
        getline(cin, str);
        assert(write(fd, str.c_str(), strlen(str.c_str())) == strlen(str.c_str()));
    }
    close(fd);
    return 0;
}


cca0b8c12baa7f660ca22f51ab34d4ce.png

当写端写入数据后,读端就会立即读取。命名管道与匿名管道最大区别就在于, 匿名管道是用于有血缘关系的进程之间,而命名管道适用于毫不相干的进程之间


目录
相关文章
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
308 0
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
379 0
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
252 0
|
Linux
Linux 更改共享内存tmpfs的大小
通过挂载的方式在原有目录或新建目录改造 如: [root@luozhonghua /]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/vg_luozhonghua-lv_root 21G 4.
1581 0
|
10月前
|
Linux 应用服务中间件 Shell
二、Linux文本处理与文件操作核心命令
熟悉了Linux的基本“行走”后,就该拿起真正的“工具”干活了。用grep这个“放大镜”在文件里搜索内容,用find这个“探测器”在系统中寻找文件,再用tar把东西打包带走。最关键的是要学会使用管道符|,它像一条流水线,能把这些命令串联起来,让简单工具组合出强大的功能,比如 ps -ef | grep 'nginx' 就能快速找出nginx进程。
1015 1
二、Linux文本处理与文件操作核心命令
|
10月前
|
Linux
linux命令—stat
`stat` 是 Linux 系统中用于查看文件或文件系统详细状态信息的命令。相比 `ls -l`,它提供更全面的信息,包括文件大小、权限、所有者、时间戳(最后访问、修改、状态变更时间)、inode 号、设备信息等。其常用选项包括 `-f` 查看文件系统状态、`-t` 以简洁格式输出、`-L` 跟踪符号链接,以及 `-c` 或 `--format` 自定义输出格式。通过这些选项,用户可以灵活获取所需信息,适用于系统调试、权限检查、磁盘管理等场景。
633 137
|
10月前
|
安全 Ubuntu Unix
一、初识 Linux 与基本命令
玩转Linux命令行,就像探索一座新城市。首先要熟悉它的“地图”,也就是/根目录下/etc(放配置)、/home(住家)这些核心区域。然后掌握几个“生存口令”:用ls看周围,cd去别处,mkdir建新房,cp/mv搬东西,再用cat或tail看文件内容。最后,别忘了随时按Tab键,它能帮你自动补全命令和路径,是提高效率的第一神器。
1593 58
|
JSON 自然语言处理 Linux
linux命令—tree
tree是一款强大的Linux命令行工具,用于以树状结构递归展示目录和文件,直观呈现层级关系。支持多种功能,如过滤、排序、权限显示及格式化输出等。安装方法因系统而异常用场景包括:基础用法(显示当前或指定目录结构)、核心参数应用(如层级控制-L、隐藏文件显示-a、完整路径输出-f)以及进阶操作(如磁盘空间分析--du、结合grep过滤内容、生成JSON格式列表-J等)。此外,还可生成网站目录结构图并导出为HTML文件。注意事项:使用Tab键补全路径避免错误;超大目录建议限制遍历层数;脚本中推荐禁用统计信息以优化性能。更多详情可查阅手册mantree。
1153 143
linux命令—tree
|
9月前
|
存储 安全 Linux
Linux卡在emergency mode怎么办?xfs_repair 命令轻松解决
Linux虚拟机遇紧急模式?别慌!多因磁盘挂载失败。本文教你通过日志定位问题,用`xfs_repair`等工具修复文件系统,三步快速恢复。掌握查日志、修磁盘、验重启,轻松应对紧急模式,保障系统稳定运行。
1483 2
|
10月前
|
Unix Linux 程序员
Linux文本搜索工具grep命令使用指南
以上就是对Linux环境下强大工具 `grep` 的基础到进阶功能介绍。它不仅能够执行简单文字查询任务还能够处理复杂文字处理任务,并且支持强大而灵活地正则表达规范来增加查询精度与效率。无论您是程序员、数据分析师还是系统管理员,在日常工作中熟练运用该命令都将极大提升您处理和分析数据效率。
801 16

热门文章

最新文章