Linux系统编程之无名管道

发布于:2025-02-22 ⋅ 阅读:(13) ⋅ 点赞:(0)

概述

        在Linux系统中,无名管道是一种简单的进程间通信机制。它允许一个进程创建一对文件描述符,其中一个用于读取,另一个用于写入。当一个进程通过系统调用创建了一个无名管道后,便可以将这两个文件描述符传递给它的子进程,使得父子进程之间可以进行单向的数据交换。

无名管道的特点

        无名管道的使用相对比较简单,具有以下一些显著的特点。

        1、半双工。无名管道是单向的,意味着我们不能同时从同一个管道两端既读又写。

        2、有限容量。无名管道有一个固定的缓冲区大小,默认情况下通常是64KB左右。如果写入的数据超过了这个限制,写操作将会阻塞直到有足够的空间可用。

        3、本地通信。无名管道只能在同一台机器上的进程间使用,不能跨越网络边界。

        4、有亲缘关系的进程。无名管道主要用于父子进程或者兄弟进程之间,因为只有这些进程可以共享由共同祖先创建的文件描述符。

        5、非持久化。无名管道是临时性的,当所有引用它的文件描述符都被关闭时,它就会被销毁。

无名管道的创建

        要创建一个无名管道,我们可以使用pipe函数。其函数原型如下。

int pipe(int pipefd[2]);

        各个参数和返回值的含义如下。

        pipefd:一个整型数组,用来存储两个文件描述符。数组的第一个元素是读端的文件描述符,第二个元素是写端的文件描述符。这两个文件描述符可以像普通文件一样,使用read和write函数来操作。

        返回值:成功时返回0,并且会将两个新的文件描述符填充到传入的pipefd数组中。失败时返回-1,并设置全局变量errno来表示具体的错误原因。

无名管道的使用

        一旦创建了无名管道,我们便可以利用它来进行进程间的通信。通常的做法是在父进程中创建管道,然后通过fork函数来创建子进程。接着,根据需要关闭不必要的文件描述符(比如:父进程中可能不需要读端,子进程中可能不需要写端),以确保数据流只朝一个方向进行流动。最后,父进程和子进程分别从各自的端点读取或写入数据。

        在下面的示例代码中,父进程创建了一个管道,然后调用fork来创建子进程。子进程继承了父进程的文件描述符,但随后关闭了不需要的写端。父进程则关闭了不需要的读端,并向管道中写入了一条消息。子进程从管道中读取消息,并打印到标准输出。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int pipefd[2];
    if (pipe(pipefd) == -1)
    {
        printf("pipe failed\n");
        return -1;
    }

    pid_t cpid = fork();
    if (cpid == -1)
    {
        printf("fork failed\n");
        return -1;
    }

    if (cpid == 0)
    {
        // 子进程,关闭写端
        close(pipefd[1]);

        char buf = 0;
        while (read(pipefd[0], &buf, 1) > 0)
        {
            write(STDOUT_FILENO, &buf, 1);
        }

        write(STDOUT_FILENO, "\n", 1);
        close(pipefd[0]);
        _exit(EXIT_SUCCESS);
    }
    else
    {
        // 父进程,关闭读端
        close(pipefd[0]);
        const char *pszMsg = "Hello, Hope_Wisdom";
        write(pipefd[1], pszMsg, strlen(pszMsg));
        close(pipefd[1]);

        // 等待子进程结束
        wait(NULL);
    }

    return 0;
}