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

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


目录
相关文章
|
7月前
|
缓存 监控 Linux
Linux内存问题排查命令详解
Linux服务器卡顿?可能是内存问题。掌握free、vmstat、sar三大命令,快速排查内存使用情况。free查看实时内存,vmstat诊断系统整体性能瓶颈,sar实现长期监控,三者结合,高效定位并解决内存问题。
644 0
Linux内存问题排查命令详解
|
11月前
|
缓存 Linux 数据安全/隐私保护
Linux环境下如何通过手动调用drop_caches命令释放内存
总的来说,记录住“drop_caches” 命令并理解其含义,可以让你在日常使用Linux的过程中更加娴熟和自如。
1727 23
|
监控 Linux Python
Linux系统资源管理:多角度查看内存使用情况。
要知道,透过内存管理的窗口,我们可以洞察到Linux系统运行的真实身姿,如同解剖学家透过微观镜,洞察生命的奥秘。记住,不要惧怕那些高深的命令和参数,他们只是你掌握系统"魔法棒"的钥匙,熟练掌握后,你就可以骄傲地说:Linux,我来了!
419 27
|
消息中间件 Linux
Linux中的System V通信标准--共享内存、消息队列以及信号量
希望本文能帮助您更好地理解和应用System V IPC机制,构建高效的Linux应用程序。
521 48
|
消息中间件 Linux C++
c++ linux通过实现独立进程之间的通信和传递字符串 demo
的进程间通信机制,适用于父子进程之间的数据传输。希望本文能帮助您更好地理解和应用Linux管道,提升开发效率。 在实际开发中,除了管道,还可以根据具体需求选择消息队列、共享内存、套接字等其他进程间通信方
357 16
|
缓存 NoSQL Linux
Linux系统内存使用优化技巧
交换空间(Swap)的优化 禁用 Swap sudo swapoff -a 作用:这个命令会禁用系统中所有的 Swap 空间。swapoff 命令用于关闭 Swap 空间,-a 参数表示关闭 /etc/fstab 文件中配置的所有 Swap 空间。 使用场景:在高性能应用场景下,比如数据库服务器或高性能计算服务器,禁用 Swap 可以减少磁盘 I/O,提高系统性能。
518 3
|
缓存 Linux
Linux查看内存命令
1. free free命令是最常用的查看内存使用情况的命令。它显示系统的总内存、已使用内存、空闲内存和交换内存的总量。 free -h • -h 选项:以易读的格式(如GB、MB)显示内存大小。 输出示例: total used free shared buff/cache available Mem: 15Gi 4.7Gi 4.1Gi 288Mi 6.6Gi 9.9Gi Swap: 2.0Gi 0B 2.0Gi • to
2560 2
|
7月前
|
Linux 应用服务中间件 Shell
二、Linux文本处理与文件操作核心命令
熟悉了Linux的基本“行走”后,就该拿起真正的“工具”干活了。用grep这个“放大镜”在文件里搜索内容,用find这个“探测器”在系统中寻找文件,再用tar把东西打包带走。最关键的是要学会使用管道符|,它像一条流水线,能把这些命令串联起来,让简单工具组合出强大的功能,比如 ps -ef | grep 'nginx' 就能快速找出nginx进程。
791 1
二、Linux文本处理与文件操作核心命令
|
7月前
|
Linux
linux命令—stat
`stat` 是 Linux 系统中用于查看文件或文件系统详细状态信息的命令。相比 `ls -l`,它提供更全面的信息,包括文件大小、权限、所有者、时间戳(最后访问、修改、状态变更时间)、inode 号、设备信息等。其常用选项包括 `-f` 查看文件系统状态、`-t` 以简洁格式输出、`-L` 跟踪符号链接,以及 `-c` 或 `--format` 自定义输出格式。通过这些选项,用户可以灵活获取所需信息,适用于系统调试、权限检查、磁盘管理等场景。
460 137
|
7月前
|
安全 Ubuntu Unix
一、初识 Linux 与基本命令
玩转Linux命令行,就像探索一座新城市。首先要熟悉它的“地图”,也就是/根目录下/etc(放配置)、/home(住家)这些核心区域。然后掌握几个“生存口令”:用ls看周围,cd去别处,mkdir建新房,cp/mv搬东西,再用cat或tail看文件内容。最后,别忘了随时按Tab键,它能帮你自动补全命令和路径,是提高效率的第一神器。
1237 58

热门文章

最新文章