前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Linux篇】轻松搭建命名管道通信:客户端与服务器的互动无缝连接

【Linux篇】轻松搭建命名管道通信:客户端与服务器的互动无缝连接

作者头像
熬夜学编程的小王
发布于 2025-04-22 01:26:12
发布于 2025-04-22 01:26:12
12800
代码可运行
举报
文章被收录于专栏:编程小王编程小王
运行总次数:0
代码可运行
从零开始:基于命名管道实现客户端与服务器的实时通信 命名管道是一种用于进程间通信(IPC)的机制,它通过特定的文件路径进行数据传输。客户端和服务器可以通过打开命名管道进行双向数据交换。服务器通常会创建一个命名管道并等待客户端连接,而客户端则需要访问这个管道进行通信。通信的过程基于FIFO(先进先出)原则,即先写入的数据会先被读取。通过这种方式,客户端和服务器能够实现异步通信,且数据传输简单高效。命名管道的优势在于它不需要显式的网络连接,使得在同一台机器上的进程间通信变得更加便捷。

💬 欢迎讨论:如果你在学习过程中有任何问题或想法,欢迎在评论区留言,我们一起交流学习。你的支持是我继续创作的动力! 👍点赞、收藏与分享:觉得这篇文章对你有帮助吗?别忘了点赞、收藏并分享给更多的小伙伴哦!你们的支持是我不断进步的动力! 🚀分享给更多人:如果你觉得这篇文章对你有帮助,欢迎分享给更多对Linux OS感兴趣的朋友,让我们一起进步!

一. 命名管道

1.1 基本概念

命名管道(Named Pipe)是一种用于进程间通信(IPC)的机制,它允许不同进程之间通过一个命名的通道交换数据。与匿名管道不同,命名管道是通过一个系统级的文件路径来标识和访问,允许不同的进程在不同的时间、甚至不同的机器上进行通信。

允许不具有血缘关系的进程之间进行通信,数据使用FIFO原则进行数据传输。

1.2 创建命名管道

1.2.1 创建方法
  • 方法一:在命令行创建语法:

mkfifo filename

该指令将会创建命名管道filename(管道名称)。

  • 方法二: 使用相关的函数创建,语法如下:

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

参数说明:

  • pathname:这是要创建的命名管道的路径。这个路径需要是一个有效的文件路径,且在文件系统中应该是一个文件名。
  • mode:指定管道的权限,类似于文件的权限。它通常是一个由数字组成的权限值,类似于文件的权限位,例如 S_IRUSR | S_IWUSR表示用户可读可写。权限的设置遵循Linux的文件权限规则。

返回值:

  • 如果命名管道创建成功,返回 0。
  • 如果失败,返回 -1 并设置 errno 以指示错误原因。
1.2.2 示例代码:
代码语言:javascript
代码运行次数:0
运行
复制
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>

int main() {
    const char *fifo_path = "/tmp/my_fifo";//命名管道路径

    // 创建命名管道
    if (mkfifo(fifo_path, 0666) == -1) {
        perror("mkfifo failed");
        return 1;
    }
    
    printf("FIFO created successfully\n");//成功是打印该内容
    return 0;
}

在这个示例中,mkfifo 创建了一个名为 /tmp/my_fifo 的命名管道,权限设置为 0666,即文件的所有者、用户组和其他用户均可读写。

1.2.3 注意事项:
  1. 创建的管道必须由至少一个进程进行读写操作,否则可能会导致另一个进程调用 open() 时被阻塞,直到有进程打开该管道。
  2. 命名管道是一种特殊的文件,进程可以像普通文件一样对其进行读写,但它实际上是在进程之间传递数据的通道。
1.3 与匿名管道区别

特性

命名管道(Named Pipe)

匿名管道(Anonymous Pipe)

标识方式

有文件路径,可以通过路径访问

没有文件路径,仅通过管道描述符访问

作用范围

支持不同进程间通信,甚至跨系统通信

创建方式

使用mkfifo()创建

使用pipe()创建

生命周期

用户控制,管道文件存在于文件系统中

进程结束后自动销毁

阻塞行为

支持阻塞,写操作阻塞直到有读进程

支持阻塞,写操作阻塞直到有读进程

使用场景

不同进程间通信

父子进程之间通信

命名管道具有更强的灵活性,适用于跨进程、跨系统的复杂场景;而匿名管道则更简单,适用于父子进程间的简单数据传输。

  • 如何理解用户控制:

"用户控制”则表示,管道的生命周期由用户管理,用户可以决定管道的创建、删除时机,并且管道不会自动销毁,直到用户删除它。

1.4 打开原则

1.4.1 管道打开顺序
  • 写进程:可以在没有读进程存在的情况下打开管道,数据被放入管道缓冲区,直至有读进程打开并读取读取数据。如果写进程在管道缓冲区已满时继续写入,写端会发生阻塞,直到有数据可以读取。如果没有任何进程写入数据,读进程将永久阻塞。
  • 读进程:写进程必须存在,没有时读端将发生阻塞,直至有数据可以读取。如果没有任何进程写入数据,读进程将会发生永久性阻塞。
1.4.2 阻塞行为
  • 阻塞读取:如果读进程尝试从命名管道读取数据,但管道中没有数据,它会被阻塞,直到有写进程向管道写入数据。
  • 阻塞写入:如果写进程向管道写入数据,而没有任何读进程准备好读取数据(或者管道缓冲区已满),写进程将被阻塞,直到有读进程读取数据或者管道中有空闲空间。
1.4.3 管道的关闭
  • 进程关闭管道:进程在使用完管道后应该调用 close()来关闭管道。如果管道被完全关闭(即读写端都关闭),则其他试图读取或写入的进程会遇到 EOF 或 EPIPE 错误。
  • 当管道中的数据被全部读取后,读进程会收到一个“文件结束标志(EOF)”。如果继续尝试读取,将会返回 0,表示没有更多数据可读取。
1.4.4 关闭读写端的规则
  • 写端关闭时:如果写端关闭而读端仍在读取数据,读端会得到一个 EOF(文件结束符)信号,表明没有更多数据。
  • 读端关闭时:如果读端关闭而写端继续写入数据,写进程会得到一个 EPIPE 错误,表明管道的另一端已经关闭。

1.5 特点

特点与匿名管道相似,唯一不同的是它可以让毫不相干的进程之间进行通信。

二. 客户端与服务器的实现

2.1 简介

用命名管道(Named Pipe)实现客户端与服务端通信是一种常见的进程间通信(IPC)方式。在这种模式下,服务端和客户端通过一个共享的命名管道进行数据交换。命名管道提供了一个通信通道,使得它们可以在不同的进程间进行双向数据传输。由于命名管道是一种通过文件系统实现的通信机制,因此客户端和服务端可以通过文件路径访问该管道。

2.2 基本工作原理

命名管道的工作原理基于先进先出规则,即数据写入管道的顺序会按照写入的顺序被读取。它在进程间提供一个缓冲区,允许数据从一个进程流向另一个进程。

在客户端和服务端通信中,服务端通常是管道的创建者,而客户端则是通过管道进行读取和写入操作。

2.3 实现通信

2.3.1 创建并设置命名管道

为什么要使用命名管道(FIFO)?

  1. 命名管道是通过文件系统提供的通信机制,不同的进程可以通过这个管道进行数据交换。
  2. 创建管道时,可以通过文件路径访问和管理管道,因此可以跨进程通信。

创建命名管道:

  • 我们在 服务端 中创建命名管道。
代码语言:javascript
代码运行次数:0
运行
复制
int n = mkfifo(FIFO_FILE, 0666);  // 创建管道,文件名为 FIFO_FILE
if (n != 0) {
    std::cerr << "mkdir fifo error" << std::endl;
    return 1;
}
2.3.2 服务端实现(读取命名管道中的消息)
  • 服务端的主要功能:

服务端的工作是打开命名管道文件,读取客户端发送过来的消息并显示。

代码语言:javascript
代码运行次数:0
运行
复制
int fd = open(FIFO_FILE, O_RDONLY);  // 以只读方式打开命名管道
if (fd < 0) {
    std::cerr << "open fifo error" << std::endl;
    return 2;
}
  • 解释:

open() 用于打开已经创建的命名管道文件。这里我们以 O_RDONLY(只读)方式打开它,意味着服务端只是从管道中读取数据。

如果管道无法打开,输出错误信息并返回 2。

  • 读取信息
代码语言:javascript
代码运行次数:0
运行
复制
char buffer[1024];
while (true) {
    int n = read(fd, buffer, sizeof(buffer) - 1);  // 从管道读取数据
    if (n > 0) {
        buffer[n] = 0;  // 确保字符串结束
        std::cout << "client say# " << buffer << std::endl;  // 打印客户端消息
    }
}
  • 解释:

read() 函数从命名管道中读取数据,直到管道中没有数据可读。buffer 存储读取到的数据。

如果读取成功,将数据输出到控制台。

通过 n 判断读取的字节数,如果大于 0,说明读取成功。

  • 关闭管道
代码语言:javascript
代码运行次数:0
运行
复制
close(fd);  // 关闭管道
  • 解释:

完成数据读取后,关闭管道文件描述符。

2.3.3 客户端实现(向命名管道写入消息)
  • 客户端的主要功能:

客户端需要向命名管道写入消息。在每次输入后,客户端会将用户输入的消息写入管道,供服务端读取。

代码语言:javascript
代码运行次数:0
运行
复制
int fd = open(FIFO_FILE, O_WRONLY);  // 以只写方式打开命名管道
if (fd < 0) {
    std::cerr << "open fifo error" << std::endl;
    return 2;
}
  • 解释:

open() 用于打开管道文件,O_WRONLY 表示只写打开管道。客户端仅通过该管道写入数据。

如果打开失败,输出错误并返回 2。

发送信息:

代码语言:javascript
代码运行次数:0
运行
复制
while (true) {
    std::cout << "Please Enter# ";
    std::string message;
    std::cin >> message;  // 从用户输入读取消息

    int n = write(fd, message.c_str(), message.size());  // 将消息写入管道
    if (n > 0) {
        // 写入成功
    }
}
  • 解释:

std::cin >> message 用于从用户输入获取消息。

write() 用于将消息写入管道。如果消息成功写入,n 返回写入的字节数。

关闭管道:

代码语言:javascript
代码运行次数:0
运行
复制
close(fd);  // 关闭管道
  • 解释:

客户端发送完消息后,关闭管道。

2.3.4 定义常量和文件路径
代码语言:javascript
代码运行次数:0
运行
复制
#pragma once
#define FIFO_FILE "fifo"  // 定义命名管道的文件路径
  • 解释:

在 common.hpp 文件中定义一个宏 FIFO_FILE,用于存储命名管道的路径。在客户端和服务端中都使用这个路径,确保一致性。

2.3.5 总结:
  1. 服务端:创建并打开命名管道,通过 read() 从管道读取客户端发送的消息,并输出到控制台。
  2. 客户端:打开命名管道,通过 write() 将用户输入的消息发送到管道。
  3. 进程之间通过 命名管道(FIFO)共享数据,命名管道提供了一个简单的方式来进行进程间通信。
  4. 客户端和服务端各自控制着管道的一端,数据的传递是同步的,即写入和读取是交替进行的。

三. 最后

本文介绍了基于命名管道(FIFO)实现客户端与服务器实时通信的过程。命名管道是一种通过文件路径进行进程间通信的机制,支持不同进程之间的数据传输,基于FIFO(先进先出)原则。通过 mkfifo() 函数可以创建命名管道,客户端和服务端通过管道文件进行数据交换。服务端创建并打开管道以读取数据,客户端通过管道向服务端写入消息。命名管道的优势在于不需要网络连接,适用于同一台机器上的进程通信。通过合适的同步与阻塞机制,客户端与服务端能够顺利实现数据传输。

完整代码(如下):

server.cc

代码语言:javascript
代码运行次数:0
运行
复制
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
#include <unistd.h>
#include "common.hpp"


int main()
{
    umask(0);
    int n = mkfifo(FIFO_FILE, 0666);
    if(n != 0)
    {
        std::cerr << "mkdir fifo error" << std::endl;
        return 1;
    }

    int fd = open(FIFO_FILE,O_RDONLY);
    if(fd < 0)
    {
        std::cerr << "open fifo error" << std::endl;
        return 2;
    }
    char buffer[1024];
    while(true)
    {
        int n = read(fd,buffer,sizeof(buffer) -1);
        if(n > 0)
        {
            buffer[n] = 0;
            std::cout << "client say# " << buffer << std::endl;
        }
    }
    
    close(fd);
    return 0;
}

client.cc

代码语言:javascript
代码运行次数:0
运行
复制
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
#include <unistd.h>
#include "common.hpp"


int main()
{
    int fd = open(FIFO_FILE,O_WRONLY);
    if(fd < 0)
    {
        std::cerr << "open fifo error" << std::endl;
        return 2;
    }
    while(true)
    {
        std::cout << "Please Enter# ";
        std::string message;
        std::cin >> message;

        int n = write(fd, message.c_str(),message.size());
        if(n > 0)
        {

        }
    }

    close(fd);
    return 0;
}

comm.hpp

代码语言:javascript
代码运行次数:0
运行
复制
#pragma once

#define FIFO_FILE "fifo"

makefile

代码语言:javascript
代码运行次数:0
运行
复制
.PHONY:all
all:client server
client:client.cc
	g++ -o $@ $^ -std=c++11
server:server.cc
	g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -f client server

上述代码可以实现两者进行通信。

演示图片(如下图):

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-04-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
【Linux】管道通信——命名管道
命名管道,也称为 FIFO(First In First Out),是一种 进程间通信(IPC) 机制,它允许不相关的进程(即没有父子关系的进程)通过文件系统中的特殊文件进行数据传输。
用户11305458
2025/02/25
4950
【Linux】管道通信——命名管道
【Linux】 管道扩展 — 开始使用命名管道
命名管道时进程间通信的一种,那么原理也就是类似的:先让不同的进程看到同一份(操作系统)资源(“一段内存”)。
叫我龙翔
2024/05/31
2750
【Linux】 管道扩展 — 开始使用命名管道
Linux进程间通信【命名管道】
命名管道通信属于 IPC 的其中一种方式,作为管道家族,命名管道的特点就是 自带同步与互斥机制、数据单向流通,与匿名管道不同的是:命名管道有自己的名字,因此可以被没有血缘关系的进程看到,意味着命名管道可以实现毫不相干的两个独立进程间通信
北 海
2023/07/01
5800
Linux进程间通信【命名管道】
【Linux】IPC 进程间通信(一):管道(匿名管道&命名管道)
为了实现两个或者多个进程实现数据层面的交互,因为进程独立性的存在,导致进程通信的成本比较高
IsLand1314
2024/11/19
4860
【Linux】IPC 进程间通信(一):管道(匿名管道&命名管道)
【Linux】进程间通信——命名管道
匿名管道只能用来进行进程间通信,让具有血缘关系的进程进行通信 让毫不相关的进程之间进行通信,就需要采用命名管道通信
lovevivi
2023/05/11
2.1K0
【Linux】进程间通信——命名管道
命名管道Linux
首先自己要用用户层缓冲区,还得把用户层缓冲区拷贝到管道里,(从键盘里输入数据到用户层缓冲区里面),然后用户层缓冲区通过系统调用(write)写到管道里,然后再通过read系统调用,被对方(读端)读取,就要从管道拷贝到读端,然后再显示到显示器上。
ljw695
2024/10/18
4120
命名管道Linux
【Linux进程#1】IPC 进程间通信(一):管道(匿名管道&命名管道)
✨ 无人扶我青云志,我自踏雪至山巅 🌏
IsLand1314
2025/06/02
1480
【Linux进程#1】IPC 进程间通信(一):管道(匿名管道&命名管道)
【Linux】进程间通信——命名管道
  匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在不相关的进程之间交换数据,可以使用命名管道来做这项工作。   在Linux系统中,命名管道(也称为FIFO,First In First Out)是一种特殊的文件类型,它允许进程间进行通信。与匿名管道不同,命名管道存在于文件系统中,并且可以被任何有适当权限的进程访问。命名管道提供了一种方法,使得不相关的进程能够通过预先定义好的路径来交换数据。
大耳朵土土垚
2024/12/04
2760
【Linux】进程间通信——命名管道
【Linux】深度探秘命名管道:Linux 进程通信的无声桥梁
文章链接:https://cloud.tencent.com/developer/article/2466294
Yui_
2024/11/18
2410
【Linux】深度探秘命名管道:Linux 进程通信的无声桥梁
匿名管道和命名管道
https://blog.csdn.net/2401_83427936/article/details/142603367
ljw695
2024/10/18
2650
匿名管道和命名管道
深入了解linux系统—— 进程间通信之管道
本篇博客所涉及到的代码一同步到本人gitee:testfifo · 迟来的grown/linux - 码云 - 开源中国
星辰与你
2025/06/08
790
深入了解linux系统—— 进程间通信之管道
【Linux篇章】进程通信黑科技:匿名管道的暗码传递与命名管道的实名使命
本文主要探讨进程间通信中的匿名管道和命名管道。将介绍匿名管道如何凭借其隐蔽性在进程间实现数据传输,以及命名管道因具备可命名的特性所带来的独特通信优势;同时会进行相关示例效果演示;代码编写;带读者一步步理解所谓的匿名管道和命名管道等。
羑悻的小杀马特.
2025/04/22
690
【Linux篇章】进程通信黑科技:匿名管道的暗码传递与命名管道的实名使命
【Linux进程通信】三、命名管道
​ 匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在不相关的进程之间交换数据,可以创建和使用 FIFO 文件来做这项工作,它经常被称为命名管道。
利刃大大
2025/03/18
1550
【Linux进程通信】三、命名管道
【进程间通信】IPC、管道pipe、命名管道FIFO
Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
mindtechnist
2024/08/08
3010
【进程间通信】IPC、管道pipe、命名管道FIFO
Linux:进程间通信(一.初识进程间通信、匿名管道与命名管道、共享内存)
这种双重性使得管道既具有机制的灵活性,又具有文件的可操作性。它可以在不同的进程之间建立连接,实现数据的传递和共享,同时也可以通过标准的文件操作接口进行访问和控制。
是Nero哦
2024/07/09
6070
Linux:进程间通信(一.初识进程间通信、匿名管道与命名管道、共享内存)
【Linux】命名管道
命名管道由mkfifo创建,是一个文件,打开要用open打开 命名管道与匿名管道之间唯一的区别就是它们创建和打开的方式不同,其他基本上相同 命名管道也只能和有“血缘”的进程进行通信
s-little-monster
2025/03/04
3800
【Linux】命名管道
【Linux】进程间通信:命名管道
管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道
用户11029103
2025/03/14
1360
【Linux】进程间通信:命名管道
进程间通信Linux
首先自己要用用户层缓冲区,还得把用户层缓冲区拷贝到管道里,(从键盘里输入数据到用户层缓冲区里面),然后用户层缓冲区通过系统调用(write)写到管道里,然后再通过read系统调用,被对方(读端)读取,就要从管道拷贝到读端,然后再显示到显示器上。
ljw695
2024/11/15
3300
进程间通信Linux
【Linux篇】共享内存实战:打造高性能服务端与客户端通信的终极指南(赋源码)
共享内存是一种高效的进程间通信(IPC)方式,允许多个进程访问同一块内存区域。通过共享内存,进程之间可以直接读写数据,而无需经过操作系统的中介,从而减少了上下文切换的开销。在服务端和客户端通信中,服务端通常会创建共享内存并将数据写入该区域,客户端可以直接读取该数据。由于共享内存不需要通过管道、套接字等其他通信方式,因此在高性能应用中非常有用。实现简单的服务端与客户端通信时,服务端负责创建并初始化共享内存,客户端则连接到该内存并读取或写入数据。这样,双方可以通过共享内存高效地交换信息。
熬夜学编程的小王
2025/04/25
1950
初识Linux · 命名管道
有了前文匿名管道的基础,我们介绍匿名管道的时候就轻松许多了,匿名管道和命名管道的区别主要是在于,匿名管道不需要文件路径,并且匿名管道常用于父子进程这种具有血缘关系的场景,使用命名管道的时候,我们常常用于的情况是两个进程毫无联系,使这两个毫无关系的进程可以进行通信。
_lazy
2024/11/19
2870
初识Linux · 命名管道
推荐阅读
相关推荐
【Linux】管道通信——命名管道
更多 >
目录
  • 从零开始:基于命名管道实现客户端与服务器的实时通信 命名管道是一种用于进程间通信(IPC)的机制,它通过特定的文件路径进行数据传输。客户端和服务器可以通过打开命名管道进行双向数据交换。服务器通常会创建一个命名管道并等待客户端连接,而客户端则需要访问这个管道进行通信。通信的过程基于FIFO(先进先出)原则,即先写入的数据会先被读取。通过这种方式,客户端和服务器能够实现异步通信,且数据传输简单高效。命名管道的优势在于它不需要显式的网络连接,使得在同一台机器上的进程间通信变得更加便捷。
  • 一. 命名管道
    • 1.1 基本概念
    • 1.2 创建命名管道
      • 1.2.1 创建方法
      • 1.2.2 示例代码:
      • 1.2.3 注意事项:
      • 1.3 与匿名管道区别
    • 1.4 打开原则
      • 1.4.1 管道打开顺序
      • 1.4.2 阻塞行为
      • 1.4.3 管道的关闭
      • 1.4.4 关闭读写端的规则
    • 1.5 特点
  • 二. 客户端与服务器的实现
    • 2.1 简介
    • 2.2 基本工作原理
    • 2.3 实现通信
      • 2.3.1 创建并设置命名管道
      • 2.3.2 服务端实现(读取命名管道中的消息)
      • 2.3.3 客户端实现(向命名管道写入消息)
      • 2.3.4 定义常量和文件路径
      • 2.3.5 总结:
  • 三. 最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验