Linux应用-----进程间通信

一、进程间通信目的

  • 数据传输:一个进程需要将它的数据发送给另一个进程
  • 资源共享:多个进程之间共享同样的资源。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止
  • 时要通知父进程)。
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

如何理解通信的本质问题:

(1)操作系统需要直接或者间接给通信双方的进程提供"内存空间"。

(2)要通信的进程,必须要看到同一份公共的资源

  • 模块化实现:不同通信方式本质上是操作系统不同模块提供的资源:
    • 文件系统提供→管道通信
    • System V通信模块提供→共享内存/信号量/消息队列
  • 资源类型决定通信方式:
    • 内存块→共享内存
    • 计数器→信号量
    • 队列→消息队列

二、什么是管道

管道是Unix中最古老的进程间通信的形式。

我们把从一个进程连接到另一个进程的一个数据流称为一个"管道"。

三、站在文件描述符角度-深度理解管道

管道是父进程创通过调用管道,分别以读和写方式打开一个文件,并通过fork创建子进程的方式,被子进程继承下去,进而形成一条通信管道

  • ,管道文件的作用与特点
    • 通信本质: 专门用于两个进程间通信的特殊文件类型
  • 两个进程看到同一个管道文件
    • 实现方法:通过父进程打开文件后fork创建子进程完成
      • 继承机制:子进程会继承父进程的文件描述符表内容
      • 文件标识:类似宿舍号和班级名称,通过相同文件描述符标识同一文件
  • 匿名管道的概念
    • 命名特点:内存级文件没有文件名标识
cpp 复制代码
#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<cstring>
#include<cstdio>
using namespace std;

int main()
{

    int fds[2];
    int n = pipe(fds);

    pid_t id = fork();
    if(id==0)
    {  
        close(fds[0]);
        int cnt=0;
        const char*s = "我是子进程,我正在给你发消息";
        while (1)
        {
            cnt++;
            char buffer[1024];
            snprintf(buffer,sizeof(buffer),"child->parent say:%s[%d]\n",s,cnt);
            write(fds[1],buffer,strlen(buffer));
            sleep(1);
        }
        

        exit(0);
    }
    
    close(fds[1]);

    while (1)
    {
        char buffer[1024];
        //如果管道中没有了数据,读端在读,默认会直接阻塞当前正在读取的进程。
        ssize_t s = read(fds[0],buffer,sizeof(buffer)-1);
        if(s>0)//返回值是获取字节数的个数
        {
            buffer[s]=0;
            cout<<buffer<<endl;
        }
    }

    n=waitpid(id,nullptr,0);
    close(fds[0]);
    return 0;

}

管道是一个固定大小的缓冲区,当写端一直写,读端不读,缓冲区会被写满,写满之后不能再写了,如果在写会把以前写入的数据覆盖,写端写满会发生阻塞等对方进行读取。

若是子进程写入一条消息后立即关闭写端(文件描述符),父进程读取到read返回值那就是是0。

若是读端关闭,写端口一直写,操作系统会终止写端口,会给写端口发送信号终止写端。


四、管道的五大特征

  • 文件依托性
    • 基础机制: 管道基于文件实现
    • 生命周期: 随进程创建和销毁,当所有关联进程退出时管道自动释放
    • 类比特性: 与普通文件特性一致,进程退出后相关资源自动回收
  • 血缘通信
    • 适用范围: 专用于具有血缘关系的进程间通信
      • 父子进程通信(最典型场景)
      • 兄弟进程通信(需通过共同父进程建立管道)
      • 多代进程通信(如祖父-孙子进程)
    • 实现前提: 必须在fork()前创建管道才能实现共享
  • 字节流特性
    • 数据特征: 不区分消息边界,按字节流处理
    • 读写特点:
      • 写入方不考虑接收方的数据解析需求
      • 读取方按最大可读字节数获取数据
    • 对比说明: 不同于消息队列等有明确消息边界机制
  • 半双工通信
    • 通信方向: 任一时刻只允许单向数据传输
    • 特殊形式: 单向通信是半双工的特例
    • 实现限制: 需要两个管道才能实现双向通信
  • 同步互斥机制
    • 阻塞控制:
      • 写满阻塞:管道缓冲区满时写入进程自动阻塞
      • 读空阻塞:管道空时读取进程自动阻塞
    • 异常处理:
      • 读端关闭时继续写入会触发SIGPIPE
      • 写端关闭时读取会立即返回0(EOF)
    • 保护机制: 内部实现共享资源保护,确保数据一致性
相关推荐
桌面运维家2 小时前
Windows/Linux文件访问权限修改指南
linux·运维·服务器
badhope2 小时前
Docker入门到实战全攻略
linux·python·docker·github·matplotlib
麦芽糖02192 小时前
centos虚拟机忘记密码怎么办
linux·运维·centos
ken22323 小时前
ubuntu 云镜像 2604 的内存和磁盘占用 实测
linux·运维·ubuntu
程序猿编码3 小时前
Linux 进程注入:从调试器到武器化的技术演进
linux·运维·服务器·c++·进程注入
淮北也生橘123 小时前
Linux应用开发:C标库中的操作字符串函数简单总结
linux·运维·c语言
李小白杂货铺4 小时前
网络测速脚本(MacOS和Linux平台可用)
linux·macos·脚本·curl·ping·网络测速·网络测速脚本
REDcker4 小时前
libevent、libev 与 libuv:对比、演进与实现原理
linux·c++·后端·编程·c·高并发·服务端
123过去4 小时前
impacket-mssqlclient使用教程
linux·测试工具·安全