MST

星途 面试题库

面试题:C语言匿名管道通信的基本原理

请简述在Linux环境下,C语言匿名管道通信是如何实现进程间数据传递的,包括涉及到的系统调用及其作用。
13.3万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试
  1. 匿名管道概述
    • 匿名管道是一种半双工的通信方式,数据只能单向流动,常用于具有亲缘关系(如父子进程)的进程间通信。
  2. 系统调用及作用
    • pipe函数
      • 函数原型int pipe(int pipefd[2]);
      • 作用:创建一个匿名管道。pipefd是一个由两个文件描述符组成的数组,pipefd[0]用于从管道读取数据,pipefd[1]用于向管道写入数据。若成功,返回0;若失败,返回 -1并设置errno
    • fork函数
      • 函数原型pid_t fork(void);
      • 作用:用于创建一个新进程,新进程(子进程)几乎是当前进程(父进程)的一个副本。通常在pipe调用之后使用fork,这样父子进程就可以通过之前创建的管道进行通信。父进程和子进程会共享管道的文件描述符。返回值在父进程中是子进程的进程ID,在子进程中是0,若失败返回 -1 并设置errno
    • read函数
      • 函数原型ssize_t read(int fd, void *buf, size_t count);
      • 作用:从文件描述符fd(这里是pipefd[0])中读取最多count字节的数据到缓冲区buf中。返回值为实际读取的字节数,若为0表示到达文件末尾(管道中没有数据且写端已关闭),若为 -1表示出错并设置errno
    • write函数
      • 函数原型ssize_t write(int fd, const void *buf, size_t count);
      • 作用:将缓冲区bufcount字节的数据写入到文件描述符fd(这里是pipefd[1])。返回值为实际写入的字节数,若为 -1表示出错并设置errno
  3. 实现步骤示例(以父子进程为例)
    • 父进程调用pipe创建管道。
    • 父进程调用fork创建子进程。
    • 父子进程根据需求关闭不需要的管道文件描述符(例如父进程关闭读端pipefd[0],子进程关闭写端pipefd[1],当然情况也可相反)。
    • 关闭不需要的文件描述符后,就可以在父子进程间通过writeread函数进行数据传递。例如父进程向管道写端写入数据,子进程从管道读端读取数据。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_SIZE 256

int main() {
    int pipefd[2];
    pid_t cpid;
    char buf[BUFFER_SIZE];

    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    cpid = fork();
    if (cpid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (cpid == 0) {    // 子进程
        close(pipefd[1]);  // 关闭写端
        ssize_t numRead = read(pipefd[0], buf, BUFFER_SIZE);
        if (numRead == -1) {
            perror("read");
            exit(EXIT_FAILURE);
        }
        printf("子进程读取到: %.*s\n", (int)numRead, buf);
        close(pipefd[0]);
        exit(EXIT_SUCCESS);
    } else {            // 父进程
        close(pipefd[0]);  // 关闭读端
        const char *msg = "Hello, child!";
        ssize_t numWritten = write(pipefd[1], msg, strlen(msg));
        if (numWritten == -1) {
            perror("write");
            exit(EXIT_FAILURE);
        }
        close(pipefd[1]);
        wait(NULL);
        exit(EXIT_SUCCESS);
    }
}

上述代码展示了父子进程通过匿名管道进行简单数据传递的过程。