Linux系统编程-进程间通信(IPC)常用方式详解

        进程间通信(IPC,Inter-Process Communication)是指在操作系统中,不同进程之间进行数据交换和信息传递的机制。这种通信允许正在运行的多个进程能够相互协作、共享数据或者进行同步操作,以实现更复杂的任务和功能。Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。

1.管道-pipe

管道(Pipe)是一种进程间通信(IPC)机制,允许具有亲缘关系的进程之间进行单向通信。它是Unix和类Unix操作系统中常见的IPC方式之一,通常用于在父子进程或者兄弟进程之间传递数据。

概念:

管道是一种特殊的文件描述符,它连接了两个进程,其中一个进程的输出作为另一个进程的输入。管道是单向的,即数据只能在一个方向上流动。通常有两种类型的管道:

  • 匿名管道:存在于具有亲缘关系的进程之间,通常用于父子进程之间或者通过fork()系统调用创建的进程间通信。

  • 命名管道(FIFO):是一种特殊的文件系统对象,允许不相关的进程通过文件路径来进行通信。

原理:

管道基于操作系统提供的内核缓冲区进行数据传输。在Unix系统中,管道可以通过pipe()系统调用创建。pipe()系统调用会创建一个管道,并返回两个文件描述符:

  • 第一个文件描述符用于管道的写入端(写入数据的进程将数据发送到这一端)。
  • 第二个文件描述符用于管道的读取端(读取数据的进程从这一端接收数据)。

管道的工作原理可以简单描述为:

  1. 进程A调用pipe()系统调用创建管道,得到两个文件描述符fd[0](读取端)和fd[1](写入端)。
  2. 进程A通过fork()创建进程B,此时进程A和进程B都能够访问这两个文件描述符。
  3. 进程A可以通过fd[1]写入数据到管道,而进程B可以通过fd[0]从管道中读取数据。

数据在管道中是先进先出(FIFO)的顺序进行传递,当进程向管道写入数据时,数据会被存储在内核缓冲区中,等待被读取进程读取。

局限性:

  • 单向通信:管道只支持单向数据传输,即数据只能从一个方向流动。

  • 具有亲缘关系的进程:匿名管道只能用于具有亲缘关系的进程之间,通常是父子进程或者通过fork()创建的进程。

  • 容量有限:管道的容量是有限的,通常在几千字节到几兆字节之间,这取决于操作系统的具体实现。

  • 无法进行双向通信:如果需要双向通信,通常需要创建两个管道,一个用于从父进程到子进程,另一个用于从子进程到父进程。

  • 阻塞问题:管道的读取端和写入端在一些情况下可能会发生阻塞,特别是当管道为空或者已满时。

1.1pipe()

管道(Pipe)通过pipe()系统调用来创建。pipe()函数可以在进程间创建一个管道,这个管道具有两个文件描述符:一个用于读取端,一个用于写入端。这种方式可以实现具有亲缘关系的进程之间的单向通信。

函数原型:
#include <unistd.h>

int pipe(int pipefd[2]);
参数:pipefd是一个整型数组,长度为2,用于存储管道的两个文件描述符。
pipefd[0]:用于读取管道数据的文件描述符(读取端)。
pipefd[1]:用于写入管道数据的文件描述符(写入端)。
返回值:成功时返回0,失败时返回-1,并设置errno以指示错误类型。

示例代码:父子进程使用管道pipe通信

一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信(因此也不难推出,只要两个进程中存在血缘关系,这里的血缘关系指的是具有共同的祖先,都可以采用管道方式来进行通信)。父子进程间具有相同的文件描述符,且指向同一个管道pipe,其他没有关系的进程不能获得pipe()产生的两个文件描述符,也就不能利用同一个管道进行通信。

步骤:

第一步:父进程创建管道:

第二步:父进程fork出子进程:

第三步:父进程关闭fd[0],子进程关闭fd[1]

创建步骤总结:

  • 父进程调用pipe函数创建管道,得到两个文件描述符fd[0]和fd[1],分别指向管道的读端和写端。
  • 父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管。
  • 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出,这样就实现了父子进程间通信。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>

#define BUFFER_SIZE 25

int main() {
    int pipefd[2];
    pid_t pid;
    char parent_message[BUFFER_SIZE] = "Hello, child!";
    char child_message[BUFFER_SIZE];

    // 创建管道
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    // 创建子进程
    pid = fork();

    if (pid < 0) {  // 错误处理
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid > 0) {  // 父进程
        close(pipefd[0]);  // 关闭父进程的读取端

        // 向管道写入数据
        write(pipefd[1], parent_message, strlen(parent_message) + 1);
        printf("Parent wrote: %s\n", parent_message);

        close(pipefd[1]);  // 关闭写入端

        // 等待子进程结束
        wait(NULL);
    } else {  // 子进程
        close(pipefd[1]);  // 关闭子进程的写入端

        // 从管道读取数据
        read(pipefd[0], child_message, BUFFER_SIZE);
        print
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值