进程通信--管道(存在于内核区)

在Linux中,管道(pipe)是一种用于进程间通信(IPC)的机制,它允许数据在两个进程之间单向传输。管道有两种类型:匿名管道和命名管道(FIFO)。

匿名管道

匿名管道通常用于具有父子关系的进程之间的通信。它由 pipe() 系统调用创建。匿名管道只存在于创建它的进程及其子进程之间。匿名管道创建后,生成一对文件描述符,一个用于读取,另一个用于写入。

以下是使用匿名管道进行父子进程间通信的示例:

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

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

    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]);    /* 关闭写端 */

        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 *msg = "Hello from parent";
        write(pipefd[1], msg, strlen(msg));
        close(pipefd[1]);    /* 关闭写端 */
        wait(NULL);          /* 等待子进程 */
        exit(EXIT_SUCCESS);
    }
}

命名管道(FIFO)

命名管道可以在无亲缘关系的进程之间进行通信。它在文件系统中存在,使用 mkfifo 命令或 mkfifo() 系统调用创建。命名管道通过路径名进行访问。

以下是使用命名管道进行进程间通信的示例:

  1. 创建命名管道(通常在 shell 中执行):

    mkfifo /tmp/myfifo
    
  2. 写入进程(writer.c):

    #include <fcntl.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main() {
        const char *fifo_path = "/tmp/myfifo";
        const char *msg = "Hello from writer";
        int fd = open(fifo_path, O_WRONLY);
        if (fd == -1) {
            perror("open");
            exit(EXIT_FAILURE);
        }
    
        write(fd, msg, strlen(msg));
        close(fd);
        return 0;
    }
    
  3. 读取进程(reader.c):

    #include <fcntl.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int main() {
        const char *fifo_path = "/tmp/myfifo";
        char buf[128];
        int fd = open(fifo_path, O_RDONLY);
        if (fd == -1) {
            perror("open");
            exit(EXIT_FAILURE);
        }
    
        ssize_t num_bytes = read(fd, buf, sizeof(buf) - 1);
        if (num_bytes == -1) {
            perror("read");
            exit(EXIT_FAILURE);
        }
    
        buf[num_bytes] = '\0';  // Null-terminate the string
        printf("Read from FIFO: %s\n", buf);
        close(fd);
        return 0;
    }
    

代码编译和运行

  1. 编译代码:

    gcc writer.c -o writer
    gcc reader.c -o reader
    
  2. 运行写入进程:

    ./writer
    
  3. 在另一个终端窗口运行读取进程:

    ./reader
    

总结

  • 匿名管道:适用于父子进程间的通信,使用 pipe() 系统调用创建。
  • 命名管道(FIFO):适用于无亲缘关系的进程间通信,使用 mkfifo 命令或 mkfifo() 系统调用创建。

通过管道,进程可以高效地进行数据传输,实现进程间的协同工作。

posted @ 2024-05-22 10:45  ponder776  阅读(3)  评论(0编辑  收藏  举报