linux编程之pipe()函数详解

Linux编程之pipe()函数详解

在Linux编程中,pipe()是一个重要的函数,用于在两个进程之间创建一个管道,从而实现进程间通信。本文将详细讲解pipe()函数的使用方法、注意事项及示例说明。

管道的创建

调用pipe()函数可以创建一个管道,该函数的原型如下:

#include <unistd.h>

int pipe(int pipefd[2]);

其中,pipefd是一个整型数组,用于存储管道两端的文件描述符。pipefd[0]代表读端,pipefd[1]代表写端。

需要注意的是,pipe()函数必须在创建进程之前调用,这是因为管道只能在父进程和子进程之间进行通信,而且在fork函数之后,父进程和子进程拥有相同的文件描述符表,因此在子进程调用pipe()函数创建管道已经来不及了。

管道的通信

管道的通信是通过read()write()函数完成的,其中读操作和写操作分别在不同的进程中进行。如下图所示,假设有两个进程P1和P2,通过pipe()函数创建一个管道,并且P1写入数据到管道中,P2从管道中读出数据。

+------+         +------+
|  P1  |         |  P2  |
+------+         +------+
   |  ------------->  |
   |                 |
   |                 |
   |  <-------------  |
   |                  |
+--------+         +--------+
| Write  |         |  Read  |
|  end   |         |  end   |
+--------+         +--------+

写端

在写端进程中,我们需要取得管道的写文件描述符,并通过write()函数将数据写入管道中,示例如下:

char *buffer = "Hello pipe!";

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

// 子进程中写入数据
if (fork() == 0) {
    close(pipefd[0]); // 关闭读端
    write(pipefd[1], buffer, strlen(buffer));
    close(pipefd[1]);
    exit(EXIT_SUCCESS);
}

上述代码中,先创建了一个包含字符串数据的缓冲区buffer,随后通过pipe()函数创建了一个管道,并在子进程中进行写入操作。管道的写文件描述符为pipefd[1],所以需要先关闭读端文件描述符pipefd[0],然后使用write()函数将数据写入管道,最后关闭写文件描述符pipefd[1]

读端

在读端进程中,我们需要取得管道的读文件描述符,并通过read()函数从管道中读取数据,示例如下:

char buffer[BUFSIZ];

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

// 父进程中读取数据
if (fork() > 0) {
    close(pipefd[1]); // 关闭写端
    int len = read(pipefd[0], buffer, BUFSIZ - 1);
    buffer[len] = '\0';
    printf("Received message: %s\n", buffer);
    close(pipefd[0]);
    exit(EXIT_SUCCESS);
}

上述代码中,先创建了一个缓冲区buffer,随后通过pipe()函数创建了一个管道,并在父进程中进行读取操作。管道的读文件描述符为pipefd[0],所以需要先关闭写端文件描述符pipefd[1],然后使用read()函数从管道中读取数据,并将其保存到缓冲区中,最后打印出接收到的数据并关闭读文件描述符pipefd[0]

注意事项

在使用pipe()函数时,需要注意以下几点:

  • 管道是一个单向通信机制,一端写入后只能在另一端读取,不能同时读写。
  • 管道的容量是有限的,写入数据超过管道容量时会阻塞,除非使用特殊标志。
  • 管道的文件描述符不是永久性的,程序退出时会自动关闭。

示例说明

示例一:基本使用

上述代码中的示例即为管道的基本使用示例,实现了进程间的单向通信。

示例二:多进程通信

可使用多个子进程向同一管道中写入数据,父进程从中读取,并统计接收到的数据总和。

具体实现代码及解释如下:

// 定义进程数
#define PROCESS_NUM 3

// 主函数
int main(int argc, char *argv[]) {
    char buffer[BUFSIZ];

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

    // 创建多个子进程并向管道中写入数据
    for (int i = 0; i < PROCESS_NUM; i++) {
        if (fork() == 0) { // 子进程中
            close(pipefd[0]); // 关闭读端
            sprintf(buffer, "Message from child %d\n", i);
            write(pipefd[1], buffer, strlen(buffer));
            close(pipefd[1]);
            exit(EXIT_SUCCESS);
        }
    }

    // 父进程中读取并统计数据
    close(pipefd[1]); // 关闭写端
    int sum = 0;
    for (int i = 0; i < PROCESS_NUM; i++) {
        int len = read(pipefd[0], buffer, BUFSIZ - 1);
        buffer[len] = '\0';
        printf("Received message: %s", buffer);
        sum += len;
    }
    printf("Received total %d bytes.\n", sum);
    close(pipefd[0]);
    wait(NULL);

    return 0;
}

上述代码中,先定义了一个常量PROCESS_NUM,表示创建的子进程数。随后创建了一个包含读写文件描述符的管道,并使用fork()函数创建子进程,子进程中向管道中写入一条数据,并在写入完成后关闭写文件描述符。

在父进程中,读取管道中的数据并将其累加,最终打印出接收到的总数据量,并关闭读文件描述符。

通过以上代码,我们可以实现多个子进程同时向同一管道中写入数据,而父进程从中读取,并统计接收到的数据总和,从而实现了多进程之间的通信。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:linux编程之pipe()函数详解 - Python技术站

(0)
上一篇 2023年5月25日
下一篇 2023年5月25日

相关文章

  • Python分布式异步任务框架Celery使用教程

    Python分布式异步任务框架Celery使用教程 简介 Celery是Python编写的分布式异步任务队列,是一个优秀的基于消息传递的任务队列。Celery支持任务调度和消息分发,可以根据用户的需求创建多个任务队列,优化用户的任务处理效率。 安装 安装Celery可以使用官方推荐的方式通过pip进行安装。例如: pip install celery 安装好…

    人工智能概览 2023年5月25日
    00
  • flask和vue前后端分离项目部署的示例代码

    下面我将为你详细讲解Flask和Vue前后端分离项目部署的攻略,分为以下几个步骤: 1. 开发前的准备工作 在开始开发前,我们需要准备好以下工具和环境: Python环境。推荐安装Python 3.6以上的版本。 Node.js环境。推荐安装8.11以上的版本。 Vue CLI。可使用npm install -g @vue/cli命令进行安装。 MySQL数…

    人工智能概论 2023年5月25日
    00
  • PHP调用Webservice实例代码

    下面是关于“PHP调用Webservice实例代码”的完整攻略。 什么是Webservice? WebService是一种通过网络使用web通信协议进行交互的技术。使用WebService技术能够在不同的操作系统和应用之间进行数据交换,使得互操作性更好。 PHP调用Webservice的实现方式 PHP调用Webservice可以使用SOAP(基于XML的协…

    人工智能概论 2023年5月25日
    00
  • 使用Docker Compose搭建部署ElasticSearch的配置过程

    使用Docker Compose搭建部署ElasticSearch的配置过程步骤如下: 1. 创建Docker Compose文件 首先,我们需要在本地创建一个Docker Compose文件来定义ElasticSearch容器的配置和依赖关系。以下是一个简单的例子: version: ‘3’ services: elasticsearch: image: …

    人工智能概览 2023年5月25日
    00
  • Eclipse配置python开发环境过程图解

    下面是“Eclipse配置python开发环境过程图解”的完整攻略。 1. 下载并安装Eclipse和PyDev插件 前往Eclipse官网(https://www.eclipse.org/downloads/)下载适合你操作系统的版本,然后安装。安装完成后,启动Eclipse,进入菜单“Help” – “Eclipse MarketPlace”,搜索关键字…

    人工智能概览 2023年5月27日
    00
  • 利用node.js+mongodb如何搭建一个简单登录注册的功能详解

    下面我来详细讲解利用node.js+mongodb如何搭建一个简单登录注册的功能的攻略。 基本流程 首先,我们需要搭建node.js的环境,安装对应的依赖包,包括MongoDB、Express等。然后,我们可以创建一个项目,创建一个包含login和register两个路由的express应用。在处理控制器中,我们可以使用mongoose库来操作mongodb…

    人工智能概论 2023年5月25日
    00
  • SpringFramework应用接入Apollo配置中心过程解析

    SpringFramework应用接入Apollo配置中心过程解析 简介 Apollo是携程框架部门推出的一款企业级分布式开放平台。和SpringFramework结合使用时,可以方便地实现配置的集中管理。本文将详细讲解如何在SpringFramework应用中接入Apollo配置中心。 步骤 第一步:引入Apollo依赖 在pom.xml文件中添加如下依赖…

    人工智能概览 2023年5月25日
    00
  • 浅谈tensorflow中dataset.shuffle和dataset.batch dataset.repeat注意点

    浅谈tensorflow中dataset.shuffle和dataset.batch dataset.repeat注意点 在tensorflow中,要构建高效且正确的数据输入流程,通常需要用到两个重要的函数:dataset.shuffle和dataset.batch。本文将讨论这两个函数的用法及其注意点,还会简单介绍dataset.repeat函数。 dat…

    人工智能概论 2023年5月24日
    00
合作推广
合作推广
分享本页
返回顶部