返回顶部
首页 > 资讯 > 操作系统 >【Linux】单机版QQ之管道中的命名管道
  • 679
分享到

【Linux】单机版QQ之管道中的命名管道

c++后端服务器运维 2023-09-01 10:09:02 679人浏览 薄情痞子
摘要

还记得上一篇的匿名管道吗? 文章目录 前言一、命名管道总结 前言 命名管道是什么呢? 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。 如果我们想在不相关的进程之间交换数据,可以使用FI

还记得上一篇的匿名管道吗?

文章目录


前言

命名管道是什么呢?

管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。 命名管道是一种特殊类型的文件。

一、命名管道

学习命名管道前我们先看看在命令行创建命名管道的函数mkfifo:

 fifo的意思就是first in first out也就是先进先出的意思,比如我们直接在目录下创建一个命名管道文件:

在文件的权限部分的第一个P代表的是管道文件,下面我们讲讲命名管道的原理:

同样有两个进程,上面的是父进程下面是子进程,父进程的一个3号文件描述符表中记录一个文件的地址,这也是被父进程打开的文件,当我们创建一个子进程时,想让子进程打开和父进程打开的相同的那个文件,对于操作系统来说是不会重新再创建一个相同的文件的,操作系统会查询子进程要打开的文件是否已经被打开,如果找到这个被打开的文件就把这个文件的地址填入子进程的文件描述符表中,这样子进程就指向父进程打开的这个文件了,并且在文件中会有像ret这样的变量,当我们有文件描述符指向这个文件时这个变量就会++这也就是引用计数,关闭文件后就会--。那么如何保证两个毫不相关的进程看到的是同一个文件并打开呢?其实很简单,因为文件的唯一性是用路径表示的,只要让不同的进程通过文件路径+文件名看到同一个文件并打开,就是看到了同一个资源,这就具备了进程间通信的前提

 接下来我们用代码演示命名管道,首先需要创建两个文件client.cc写客户端代码,serve.cc写服务端代码,因为这次我们要实现两个可执行程序,所以我们需要在makefile中生成两个可执行程序,makefile代码如下图:

 .PHONY后面加上all,就是说我的目标文件是all,我们让all只有依赖关系没有依赖方法,这样就会去找server和client的依赖关系,就生成了两个可执行程序。下面我们正式编写代码,还记得我们刚开始讲的mkfifo函数吗?此函数的参数需要路径和选项(下面有C库中的mkfifo函数的说明),对于路径我们直接搞一个const string类型的字符串来保存路径,因为服务端和客户端需要打开同一份文件所以我们再创建一个公共的hpp头文件,把我们刚刚定义的路径放进去:

下面我们再看一下C库中的mkfifo函数说明:

 我们可以看到此函数有两个参数,第一个参数是路径,第二个参数是mode,mode是什么呢?mode_t类型又是什么呢?实际上mode_t就是一种无符号整数,我们在讲文件的时候提到过,就是一种让你控制要创建的文件初始是什么权限,我们默认将权限给成0666。

下面我们编写服务端的代码,不知道大家还记不记得之前说过的,对于权限我们给的是0666但是经过权限掩码的影响会变成其他的,所以我们如果不想被权限掩码所影响就将默认的权限掩码设置为0。

 因为我们在创建管道文件的时候会有可能失败,所以我们用if语句判断一下,函数返回值如果等于0就是成功否则就是失败,失败我们就打印对应的错误然后返回1.下一步就是让服务端开启管道文件,开启后就可以正常通信了:

int main(){    //1.创建管道文件,我们今天只需要一次创建    umask(0);   //这个设置并不影响系统的默认设置,只会影响当前进程    int n = mkfifo(fifoname.c_str(),mode);    if (n!=0)    {        std::cout<

 开启管道文件很简单,就是打开我们创建的管道文件,这里只需要以只读方式打开就可以。同样要判断打开失败的情况,成功后我们就打印打开管道文件成功。下面我们实现开始正常通信的代码:

int main(){    //1.创建管道文件,我们今天只需要一次创建    umask(0);   //这个设置并不影响系统的默认设置,只会影响当前进程    int n = mkfifo(fifoname.c_str(),mode);    if (n!=0)    {        std::cout<0)        {            buffer[n] = 0;            std::cout<<"client# "<

当我们正常通信的时候需要从缓冲区读数据所以先创建一个缓冲区,缓冲区大小设置为宏放在公共头文件中,因为我们把读到的数据当字符串看,所以在调用read函数的时候要让sizeof-1不要读\0,然后把缓冲区初始化一下对于C语言,直接在0位置放个\0就会认为是空字符串。然后我们判断函数返回值,如果已经读到数据结尾我们就在最后的位置放一个\0,因为我们打印字符串的时候是按照C语言的标准打印,而C语言字符串必须以\0结尾,因为服务端接收客户端发来的消息,所以在打印字符串前面加上客户端的名称。当返回值等于0说明客户端不在写东西了,客户端已经退出了,客户端都退出了就让服务端也退出,else就是读取失败,打印失败原因即可。通信结束后我们关闭管道文件即可。下面我们实现客户端:

#include #include #include #include #include #include #include #include "comm.hpp"#include int main(){    //1.不需要创建管道文件,只需要打开对应的文件即可    int wfd = open(fifoname.c_str(),O_WRONLY);    if (wfd<0)    {        std::cerr<

客户端不需要创建管道文件,因为服务端已经创建了所以我们和服务端一样打开即可,打开后因为我们的客户端要写入消息所以以只写方式打开,当打开函数的返回值小于0直接打印报错信息,接下来我们实现通信方式:

int main(){    //1.不需要创建管道文件,只需要打开对应的文件即可    int wfd = open(fifoname.c_str(),O_WRONLY);    if (wfd<0)    {        std::cerr<=0);        (void)n;    }    close(wfd);    return 0;}

 同样我们要先创建一个缓冲区,然后直接循环写入消息,然后将写入的消息放到我们的缓冲区中,用一个指针接收客户输入的字符串,如果成功了这个指针保存的就是字符串的起始地址,我们在接收字符串的时候并不需要考虑\0,因为fgets这是C语言函数会自动加上\0的,断言一下空指针,然后将指针强转是为了防止出现在release版本变量被定义但是却没有使用的情况。buffer(len-1)是什么意思呢?这里其实是因为我们客户端输入字符串后会按一下回车,而回车也会被放入缓冲区中,这样的话在打印的时候服务端会多一行空白,所以我们把回车删掉就没有问题了。接下来我们让客户端输入quit的时候就退出程序,因为我们在服务端设置的是只要客户端退出服务端也就跟着退出了。然后我们向文件里写数据,把我们缓冲区的数据写到文件中,在这里同样不用考虑\0,因为只有C语言规定字符串后面必须加\0,而write是系统接口不会考虑\0的。做完这一步后我们断言一下函数返回值,不让返回值大于等于0的意思是如果是空串或者错误就不去写入了。然后同样强转一下刚刚的返回值n。最后我们将文件关闭即可,下面我们就试试可以运行吗:

运行的时候我们必须开两个窗口,当创建好两个可执行程序后,我们先运行服务端程序,这个时候程序会卡着不动,因为服务端要等待客户端打开同一个文件所以我们在运行客户端:

 这样我们就完成了命名管道的通信,这里还有一个问题就是当我们运行一次程序后就有了管道文件下一次运行程序会出现文件已经存在的报错,所以我们可以直接在服务端关闭文件后取消链接这个文件:

 这样的话我们每次运行程序就不用先将管道文件删除再运行了。

下面我们将这个命名管道改为用户每输入一个字符,服务端就相应的输出一个字符,大家可以理解为就像我们将手机投屏到电脑上手机上做什么操作电脑屏幕就是什么操作。

因为我们前面的实现每次需要输入回车服务端才会显示消息,现在我们需要不输入回车就写入内容的函数,这里我们用的getch函数,由于getch需要用到ncurses库,所以我们先安装这个库:

(按照ncurses库这个方法我们没有搞定,如果有搞定的小伙伴可以私信我哦~成功的方法在下面我用红字提醒出来了可直接找到后用系统方法)

 如果大家是普通用户的话前面记得加上sudo提权。安装好后我们在刚刚的代码中加上这个库的头文件:

 因为我们是在客户端完成这个操作所以只需要在client.cc文件中包上这个头文件即可。然后我们修改一下client.cc文件中的代码:

 考虑到大家可能不熟悉getch这个函数,下面我们把这个函数的文档找出来:

 修改完成后下面我们把代码运行起来:

 由于编译不通过是因为我们没有引入client的库,所以我们引入一下:

 引入后我们重新生成一下可执行文件:

 运行后我们发现服务端不能正常打印了,其实原因在于函数的返回值问题,我们刚刚看文档人家的返回值是int类型,结果我们用char类型接收了,所以就出错了,下面我们修改一下代码:

由于我们不知道返回值是什么,所以我们先在代码中直接打印一下返回值:

 通过打印我们发现返回值为-1:

 然后我们将代码修改为当返回值为-1我们就继续读取字符,但是在运行的过程中由于此方法有一些错误导致还是不能成功,所以我们下面直接用系统方法不用库方法:

 然后我们在服务端接收的时候不打印前面的客户端名称了,直接就是接收什么打印什么(在这里记得刷新缓冲区):

 然后下面我们运行起来:

 这样我们就实现了一开始的功能,通过以上管道的学习相信大家能明白如何创建命名管道以及使用,上面我们使用的系统方法也是从网络上搜的,如果有什么错误还请见谅。

匿名管道与命名管道的区别: 匿名管道由 pipe 函数创建并打开。 命名管道由 mkfififo 函数创建,打开用 open FIFO (命名管道)与 pipe (匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。

命名管道的打开规则:

如果当前打开操作是为读而打开 FIFO O_NONBLOCK disable :阻塞直到有相应进程为写而打开该 FIFO O_NONBLOCK enable :立刻返回成功 如果当前打开操作是为写而打开 FIFO O_NONBLOCK disable :阻塞直到有相应进程为读而打开该 FIFO O_NONBLOCK enable :立刻返回失败,错误码为 ENXio

总结

命名管道可用于同一主机上的任意进程间通信,并且管道通信的本质是通过内核中一块缓冲区(内存)时间数据传输,而命名管道的管道文件只是一个标识符,用于让多个进程能够访问同一块缓冲区,并且管道是半双工通信,是可以选择方向的单向通信。命名管道和匿名有一个相同点,就是他们的本质都是内核中的一块缓冲区。同时补充一点,管道的生命周期是随进程的,本质是内核中的缓冲区,命名管道文件只是标识,用于让多个进程找到同一块缓冲区,删除后,之前已经打开管道的进程依然可以通信。

来源地址:https://blog.csdn.net/Sxy_wspsby/article/details/130414958

--结束END--

本文标题: 【Linux】单机版QQ之管道中的命名管道

本文链接: https://lsjlt.com/news/388188.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 【Linux】单机版QQ之管道中的命名管道
    还记得上一篇的匿名管道吗? 文章目录 前言一、命名管道总结 前言 命名管道是什么呢? 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。 如果我们想在不相关的进程之间交换数据,可以使用FI...
    99+
    2023-09-01
    c++ 后端 服务器 运维
  • Linux中的管道和命名管道有什么用
    小编给大家分享一下Linux中的管道和命名管道有什么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在 Linux 中,pipe 能让你将一个命令的输出发送给另一...
    99+
    2023-06-16
  • Linux中管道及有名管道的示例分析
    小编给大家分享一下Linux中管道及有名管道的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!管道及有名管道     ...
    99+
    2023-06-13
  • Python进程间通信之命名管道(Win
    前面文章说了一下 Linux 命名管道的实现,今天看看 Windows 上我们怎么实现。 在 Windows 上的命名管道主要是通过调用 win32 api 的以下方法来实现的: - win32pipe.CreateNamedP...
    99+
    2023-01-31
    管道 进程 通信
  • 【Linux】进程间通信(万字详解)—— 匿名管道 | 命名管道 | System V | 共享内存
    🌈欢迎来到Linux专栏~~进程通信 ...
    99+
    2023-08-22
    linux 服务器 unix
  • Linux的管道命令怎么用
    这篇文章主要介绍“Linux的管道命令怎么用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Linux的管道命令怎么用”文章能帮助大家解决问题。管道是一种多个进程之间进行通信机制,因为管道传输数据具有...
    99+
    2023-06-28
  • Linux中有名管道是什么意思
    这篇文章主要介绍Linux中有名管道是什么意思,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、管道的概念管道,又名「无名管理」,或「匿名管道」,管道是一种非常基本,也是使用非常频繁的IPC方式。1. 管道本质管道的...
    99+
    2023-06-15
  • Windows命名管道的优势有哪些
    Windows命名管道的优势包括: 可以在不同的进程之间进行通信。命名管道允许不同进程之间进行双向通信,使得进程可以共享数据和信...
    99+
    2023-10-22
    Windows
  • linux中shell管道命令pipe怎么用
    这篇文章主要介绍了linux中shell管道命令pipe怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。管道命令操作符是:”|”,它仅能处理经由前面一个指令传出的正确输出...
    99+
    2023-06-13
  • 如何在LINUX中使用管道命令
    如何在LINUX中使用管道命令?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。打开LINUX,我们可以选用UBUNTU操作系统。找到左边的TERMINAL,并且打开窗口。|前...
    99+
    2023-06-13
  • Linux系统中管道命令是什么
    这篇文章给大家分享的是有关Linux系统中管道命令是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。管道命令是指处理经由前面一个指令传出的正确输出信息,对错误信息信息没有直接处理能力。然后,传递给下一个命令,作...
    99+
    2023-06-28
  • linux pipe无名管道的作用是什么
    Linux pipe无名管道是一种进程间通信机制,用于在两个进程之间传递数据。它允许一个进程的输出作为另一个进程的输入,从而实现进程...
    99+
    2023-08-22
    linux pipe
  • linux管道的实现机制是什么
    今天小编给大家分享一下linux管道的实现机制是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解...
    99+
    2023-02-07
    linux
  • linux中管道的作用有哪些
    在Linux中,管道(|)的作用有以下几个方面:1. 连接命令:管道可以将一个命令的输出作为另一个命令的输入,实现两个或多个命令之间...
    99+
    2023-09-29
    linux
  • linux中管道符的作用是什么
    本文小编为大家详细介绍“linux中管道符的作用是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“linux中管道符的作用是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。在linux中,管道符是“|”,主...
    99+
    2023-07-02
  • Redis中管道机制的示例分析
    这篇文章将为大家详细讲解有关Redis中管道机制的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Pipeline简介Redis客户端执行一条命令:发送命令命令排队...
    99+
    2024-04-02
  • linux中的管道与重定向是什么
    这篇文章主要介绍了linux中的管道与重定向是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇linux中的管道与重定向是什么文章都会有所收获,下面我们一起来看看吧。 ...
    99+
    2023-04-20
    linux
  • 系统管理员应该知道的 20 条 Linux 命令
    在这个全新的工具和多样化的开发环境井喷的大环境下,任何开发者和工程师都有必要学习一些基本的系统管理命令。特定的命令和工具包可帮助开发者组织、排查故障并优化他们的应用程序,而且当出现错误时,也可以为运维人...
    99+
    2022-06-03
    Linux Python Linux
  • Linux 下xargs命令详解及xargs与管道的区别
    为什么要用xargs,问题的来源 在工作中经常会接触到xargs命令,特别是在别人写的脚本里面也经常会遇到,但是却很容易与管道搞混淆,本篇会详细讲解到底什么是xargs命令,为什么要用xargs命令以及与管...
    99+
    2022-06-04
    详解 管道 命令
  • linux中管道及重定向的示例分析
    这篇文章主要介绍了linux中管道及重定向的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在linux系统中,大多数命令很简单,很少出现复杂功能的命令,每个命令往往实...
    99+
    2023-06-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作