Linux IPC(Inter-Process Communication,进程间通信)之管道学习
发布日期:2021-05-20 12:34:36 浏览次数:21 分类:精选文章

本文共 3855 字,大约阅读时间需要 12 分钟。

Unix管道详解

1. 标准流管道

标准流管道是Unix系统中最基本的通信机制。通过标准流管道,可以在不同进程之间实现文件式的数据传输(也称为信道),常用的函数包括popenpclose。这种方式主要用来创建连接另一个进程的管道。

关于popen的具体实现,您可以参考这篇[博文],该博文对popen函数有详细的介绍。


2. 无名管道(PIPE)

无名管道是一种特殊的文件类型,只能在亲缘关系进程间通信(如父子进程或兄弟进程之间)。无名管道支持半双工通信,即具有固定的读端(read)和固定的写端(write)。与普通文件不同,无名管道的数据总是在内存中存储。

无名管道的函数原型如下:

#include 
int pipe(int fds[2]);

返回两个文件描述符(file descriptor):fds[0]用于读取,fds[1]用于写入。需要注意的是,两个进程必须有继承关系(如父子进程)才能重用这对描述符。

以下是一个示例代码:

int main() {    int fds[2];    if (pipe(fds) == -1) {        perror("pipe:");        return 0;    }    char buf[1024] = "";    if (fork() == 0) {        close(fds[1]);        while (memset(buf, 0, sizeof(buf))) {            if (read(fds[0], buf, 1024) == 0) {                break;            }            printf("child:read:");            puts(buf);        }        exit(1);    } else {        close(fds[0]);        char p[1024];        char *p = "Hello world!";        while (memset(buf, 0, sizeof(buf))) {            if (fgets(buf, 1024, stdin) != NULL) {                write(fds[1], buf, 1024);            }        }        close(fds[1]);        printf("parent, finish\n");        wait(NULL);    }}

3. 命名管道(FIFO)

无名管道的使用范围有限,只支持亲缘关系进程间通信。命名管道(FIFO,First-In-First-Out)突破了这一限制,允许不相关进程之间通信。通过指定路径名,用户可以创建一个有名管道,方便不同进程之间的通信。


3.1 创建与删除FIFO文件

创建命名管道与创建普通文件类似,但创建的文件类型为FIFO。创建FIFO文件的函数原型如下:

#include 
#include
int mkfifo(const char *pathname, mode_t mode);

参数说明:

  • pathname:指定要创建的FIFO文件的全路径名。
  • mode:文件的访问权限模式。

示例:

#include 
#include
#include
#include
int main(int argc, char *argv) { if (mkfifo(argv[1], 0666) == -1) { perror("mkfifo:"); return 1; } unlink(argv[1]); return 0;}

3.2 打开与关闭FIFO文件

打开FIFO文件的方式与普通文件类似,使用open函数。若以读取方式打开FIFO文件(O_RDONLY),则可以读取写入该文件的数据;若以写入方式打开(O_WRONLY),则可以向文件中写入数据。


3.3 读写FIFO文件

读取FIFO文件的方式如下:

char buf[1024] = "";if (read(fd_recv, buf, 1024) != 0) {    write(1, buf, strlen(buf));}

写入FIFO文件的方式如下:

char buf_send[1024] = "";while (fgets(buf_send, 1024, stdin) != NULL) {    write(fd_send, buf_send, strlen(buf_send));}

3.4 命名管道的通信示例

下面是两个程序的示例:pork_send.cpork_recv.c,它们通过FIFO进行聊天通信。

pork_send.c

#include 
#include
#include
#include
#include
#include
int main(int argc, char *argv) { if (mkfifo(argv[1], 0666) == -1) { perror("mkfifo:"); return 1; } int fd_send, fd_recv; fd_send = open(argv[1], O_WRONLY); fd_recv = open(argv[2], O_RDONLY); char buf_recv[1024] = ""; char buf_send[1024] = ""; printf("opening!\n"); if (fork() == 0) { close(fd_send); while (memset(buf_recv, 0, sizeof(buf_recv))) { if (read(fd_recv, buf_recv, 1024) == 0) { break; } printf("child:read:"); puts(buf_recv); } close(fd_recv); exit(1); } close(fd_recv); while (memset(buf_send, 0, sizeof(buf_send))) { fgets(buf_send, 1024, stdin); if (fgets(buf_send, 1024, stdin) == NULL) { break; } write(fd_send, buf_send, strlen(buf_send)); } close(fd_send); wait(NULL); return 0;}

pork_recv.c

#include 
#include
#include
#include
#include
#include
int main(int argc, char *argv) { if (mkfifo(argv[2], 0666) == -1) { perror("mkfifo:"); return 1; } int fd_send, fd_recv; fd_recv = open(argv[1], O_RDONLY); fd_send = open(argv[2], O_WRONLY); char buf_recv[1024] = ""; char buf_send[1024] = ""; printf("opening!\n"); if (fork() == 0) { close(fd_send); while (memset(buf_recv, 0, sizeof(buf_recv))) { if (read(fd_recv, buf_recv, 1024) == 0) { break; } printf("child:read:"); puts(buf_recv); } close(fd_recv); exit(1); } close(fd_recv); while (memset(buf_send, 0, sizeof(buf_send))) { fgets(buf_send, 1024, stdin); write(fd_send, buf_send, strlen(buf_send)); } close(fd_send); wait(NULL); return 0;}

以上就是对Unix管道的详细说明,包括标准流管道、无名管道和命名管道的使用方法。希望这些内容能为您提供有价值的信息!

上一篇:codeforces 460C - Present 二分加模拟
下一篇:codeforce 460B Little Dima and Equation

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月29日 06时48分29秒