【无标题】命名管道(Named Pipe)是一种在操作系统中用于**进程间通信(IPC)** 的机制

命名管道(Named Pipe)是一种在操作系统中用于进程间通信(IPC) 的机制,它允许不相关的进程(甚至不同用户的进程)通过一个可见的文件系统路径进行数据交换。与匿名管道(仅存在于内存,且只能用于父子进程间通信)不同,命名管道有一个持久化的文件系统入口,因此适用范围更广。

核心特性

  1. 文件系统可见性

    命名管道在文件系统中以特殊文件的形式存在(类型为 p,可通过 ls -l 查看),路径通常由用户指定(如 /tmp/my_pipe)。进程通过打开该路径来连接管道。

  2. 双向或单向通信

    支持半双工 (默认,数据单向流动)或全双工(需特殊配置)通信,具体取决于打开方式(读/写模式)。

  3. 阻塞特性

    • 若进程以只读模式打开管道,会阻塞直到另一个进程以写模式打开它。
    • 若进程以只写模式打开管道,会阻塞直到另一个进程以读模式打开它。
    • 读写操作也可能阻塞(如管道为空时读操作阻塞,管道满时写操作阻塞)。
  4. 跨进程通信

    可用于任意进程间(包括无亲缘关系的进程、不同用户的进程,甚至跨网络的进程,如通过 NFS 共享的命名管道)。

命名管道的创建与使用(以 Linux 为例)

1. 命令行创建(mkfifo)

通过 mkfifo 命令可直接在文件系统中创建命名管道:

bash 复制代码
mkfifo /tmp/my_named_pipe  # 创建命名管道
ls -l /tmp/my_named_pipe   # 查看类型(显示为 p 开头)
# 输出示例:prw-r--r-- 1 user user 0 8月 10 10:00 /tmp/my_named_pipe
2. 编程创建(C 语言)

使用 mkfifo() 系统调用在程序中创建:

c 复制代码
#include <sys/stat.h>  // 包含 mkfifo 声明

int main() {
    const char *pipe_path = "/tmp/my_pipe";
    mode_t mode = 0666;  // 权限:允许读写

    // 创建命名管道,成功返回 0,失败返回 -1
    if (mkfifo(pipe_path, mode) == -1) {
        perror("mkfifo failed");
        return 1;
    }
    return 0;
}

进程通信示例(读写操作)

命名管道的通信流程通常是:一个进程写数据,另一个进程读数据 ,通过文件操作函数(openreadwriteclose)实现。

写进程(发送数据)
c 复制代码
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main() {
    const char *pipe_path = "/tmp/my_pipe";
    const char *msg = "Hello from writer!";

    // 以只写模式打开管道(O_WRONLY)
    int fd = open(pipe_path, O_WRONLY);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }

    // 向管道写入数据
    write(fd, msg, strlen(msg));
    printf("Writer sent: %s\n", msg);

    close(fd);  // 关闭管道
    return 0;
}
读进程(接收数据)
c 复制代码
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main() {
    const char *pipe_path = "/tmp/my_pipe";
    char buf[1024];
    ssize_t bytes_read;

    // 以只读模式打开管道(O_RDONLY)
    int fd = open(pipe_path, O_RDONLY);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }

    // 从管道读取数据
    bytes_read = read(fd, buf, sizeof(buf)-1);
    if (bytes_read > 0) {
        buf[bytes_read] = '\0';  // 手动添加字符串结束符
        printf("Reader received: %s\n", buf);
    }

    close(fd);  // 关闭管道
    return 0;
}

运行方式

  1. 先运行读进程(会阻塞等待写进程连接)。
  2. 再运行写进程(发送数据后,读进程会立即接收并输出)。

关键注意事项

  1. 管道生命周期

    命名管道的文件系统入口在创建后会一直存在,直到被 unlink()rm 命令删除。即使所有进程关闭管道,文件路径仍保留。

  2. 阻塞与非阻塞

    默认情况下,openreadwrite 操作会阻塞。若需非阻塞模式,可在 open 时添加 O_NONBLOCK 标志:

    c 复制代码
    int fd = open(pipe_path, O_RDONLY | O_NONBLOCK);  // 非阻塞读
  3. 数据传输特性

    • 数据是流式的(无消息边界),读进程需自行处理数据分割(如约定换行符为结束标志)。
    • 数据一旦被读取就会从管道中移除,不会像普通文件那样保留。
  4. 权限控制

    创建时的 mode 参数(如 0666)会结合进程的 umask 确定最终权限,需确保通信进程有足够的读写权限。

  5. 与匿名管道的对比

    特性 命名管道(Named Pipe) 匿名管道(Anonymous Pipe)
    存在形式 文件系统中的特殊文件 内存中的文件描述符
    通信范围 任意进程(包括无亲缘关系) 仅限父子/兄弟进程
    创建方式 mkfifo()mkfifo 命令 pipe() 系统调用
    持久性 管道文件持久存在,直到删除 进程退出后自动销毁

应用场景

  • 命令行工具间的通信(如 mkfifo 结合 catecho 等命令)。
  • 后台服务程序与前端程序的交互(如服务器进程接收客户端命令)。
  • 日志收集(多个进程向管道写入日志,一个进程统一处理)。

命名管道是一种简单高效的 IPC 机制,适用于需要跨进程传递流式数据的场景,但其功能相对基础,复杂场景可能需要结合消息队列、共享内存等其他 IPC 方式。

相关推荐
ximy13351 天前
AI服务器工作之服务器的种类分类
运维·服务器
恒创科技HK1 天前
香港服务器CPU中E5和Gold的区别
运维·服务器
Han.miracle1 天前
数据结构——二叉树的从前序与中序遍历序列构造二叉树
java·数据结构·学习·算法·leetcode
黄沐阳1 天前
stp,rstp,mstp的区别
服务器·网络·php
Le1Yu1 天前
分布式事务以及Seata(XA、AT模式)
java
一张假钞1 天前
Ubuntu SSH 免密码登陆
linux·ubuntu·ssh
清静诗意1 天前
在 Ubuntu 上安装 MinIO 并使用 Python 封装类操作对象存储
服务器·minio
寒山李白1 天前
关于Java项目构建/配置工具方式(Gradle-Groovy、Gradle-Kotlin、Maven)的区别于选择
java·kotlin·gradle·maven
Wang's Blog1 天前
Linux小课堂: 文件操作警惕高危删除命令与深入文件链接机制
linux·运维·服务器
无妄无望1 天前
docker学习(4)容器的生命周期与资源控制
java·学习·docker