Linux间进程通信

进程间通信

进程间通信(简称IPC)是指多个进程之间传输数据或共享信息的机制。

通信目的
数据交换,共享资源,进程同步,消息传递。

实现原理
通信进程能够访问相同的内存区域。

进程间通信的方法

分为四大类:管道,System VIPC,POSIX IPC,套接字。
以下是对表格内容的提取整理,按照 方法分类 梳理各类进程间通信(IPC)的关键信息:

1. 管道(Pipe)

通信名称 描述 特点
无名管道 亲缘关系进程间通信 仅支持父子/兄弟进程
命名管道 任意进程间通信 需通过路径名标识管道

2. System V IPC

通信名称 实现方式 核心功能
消息队列 IPC 命名空间 基于消息传递数据
信号量 IPC 命名空间 实现进程间同步(如互斥锁)
共享内存 IPC 命名空间 + 内存映射 高效共享内存传递数据

3. POSIX IPC

通信名称 实现方式 核心功能
消息队列 文件系统(文件标识) 基于消息传递数据
信号量 文件系统(文件标识) 实现进程间同步
共享内存 文件 + 内存映射 高效共享内存传递数据

4. 套接字(Socket)

通信名称 描述 适用场景
socket 网络编程专题介绍 支持跨主机/跨网络通信

无名管道

介绍

无名管道用在具有亲缘关系的进程之间的单向通信。

特点

  • 半双工
  • 字节流通信,数据格式由用户自定义
  • 多用于父子进程间通信

实现原理

父进程调用pipe函数创建两个文件,读管道文件和写管道文件。这两个文件的文件节点为pipe inode。
父子进程都能看到操纵管道,管道可以看作是缓冲区。

半双工原理
由于父进程和子进程都在写文件时,都写入了管道,读取时也都是在读取管道,没有办法区分。

全双工通信
使用两个通道

为什么只能亲缘关系
因为文件表不相同

编程实现

fork()
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;

创建无名管道

int pipe(int pipefd[2]);
int pipe2(int pipeefd[2],int flags);

pipefd[0]:读文件描述符
pipefd[1]:写文件描述符

  • flags

    • O_NONBLOCK:设置非阻塞模式,读取和写入管道不会阻塞进程。
    • O_CLOEXEC :设置在execve系统调用执行时关闭管道
  • 返回值

    • 成功返回0
    • 失败返回-1,并设置errno

关闭、读写、初始化

int close(int fd);//关闭
ssize_t read(int fd, void *buf, size_t count);//读写
ssize_t write(int fd, const void *buf, size_t count);
//初始化
int fd[2] = {0}; 
//fd[0]:管道的读端(文件描述符,指向内核管道的读缓冲区)。
//fd[1]:管道的写端(文件描述符,指向内核管道的写缓冲区)。

完整流程演示

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>

#define TEST_STRING "Hello, Pipe!" 

int fd[2] = {0}; //初始化

void test() { 
  pid_t pid = fork(); //创建子进程
  if (pid == 0) { 
    close(fd[1]); // 子进程关闭写端
    char rbuf[100];
    while (1) { 
      memset(rbuf, 0, sizeof(rbuf));
      int n = read(fd[0], rbuf, sizeof(rbuf)); //从管道读端 fd[0] 读取数据,
      if (n == 0) { // 写端关闭,退出循环
        printf("Child: Pipe EOF, exit.\n");
        break; 
      }
      printf("Child: Read %d bytes: %s\n", n, rbuf);
    }
    close(fd[0]); //子进程关闭读端(退出循环后执行)
    _exit(0); // 子进程直接退出(避免执行父进程逻辑)
  } else if (pid > 0) { 
    close(fd[0]); // 父进程关闭读端
  }
}

int main(int argc, char *argv[]){ 
  if (pipe(fd) == -1) { // 检查 pipe 创建失败
    perror("pipe");
    return 1;
  }
  test(); 

  // 父进程写 5 次后退出
  for (int i = 0; i < 5; i++) { 
    write(fd[1], TEST_STRING, strlen(TEST_STRING)); 
    sleep(1); 
  }
  close(fd[1]); // 父进程关闭写端(子进程会收到 EOF)
  printf("Parent: Close write end, exit.\n");
  return 0; 
}

命名管道

介绍

FIFO文件(也称为命名管道)是一种特殊类型的文件,在Linux中用于进程间通信。FIFO文件允许不相关的进程通过读取和写入相同的文件来通信。

特点

  • FIFO文件位于文件系统中,可以像其他文件一样进行访问和管理。
  • FIFO文件可以通过名称进行识别和引用,而不仅仅依赖于文件描述符。
  • FIFO文件可以在不同的进程之间进行双向通信,允许同时进行读取和写入操作。

实现原理

进程通过mkinfo函数创建一个FIFO文件,FIFO文件对应一个fifo inode,fifo inodepipe inode底层实现相同。
命名管道通过mkinfo创建完后,进程调用open打开FIFO文件,由于每个文件都对应唯一的inode节点,所以多个进程都是打开相同的inode节点,成功打开FIFO文件后,进程能正常读写管道完成进程间通信。

编程实现

创建命名管道

int mkfifo(const char *pathname,mode_t mode);

参数
pathname:命名管道的路径
mode:创建的权限

返回值
成功返回0,失败返回-1,并设置errno

管道操作

使用IO open,write,read,close实现打开,写,读操作。

System V消息队列

简介

允许多个进程同时向消息队列中写入和读取消息。
通过消息优先级机制,可以优先处理重要的消息。

实现原理

具有相同IPC命名空间的进程能够访问IPC命名空间相同的内存空间。

ftok函数:用于生成Svstem V唯一键值。
msgget:通过key查找IPC对象。

posted @ 2025-07-25 21:19  MillionMind  阅读(27)  评论(0)    收藏  举报