帮助文档
专业提供香港服务器、香港云服务器、香港高防服务器租用、香港云主机、台湾服务器、美国服务器、美国云服务器vps租用、韩国高防服务器租用、新加坡服务器、日本服务器租用 一站式全球网络解决方案提供商!专业运营维护IDC数据中心,提供高质量的服务器托管,服务器机房租用,服务器机柜租用,IDC机房机柜租用等服务,稳定、安全、高性能的云端计算服务,实时满足您的多样性业务需求。 香港大带宽稳定可靠,高级工程师提供基于服务器硬件、操作系统、网络、应用环境、安全的免费技术支持。
服务器资讯 / 香港服务器租用 / 香港VPS租用 / 香港云服务器 / 美国服务器租用 / 台湾服务器租用 / 日本服务器租用 / 官方公告 / 帮助文档
【Linux】单机版QQ之管道中的命名管道
发布时间:2024-02-27 20:23:47   分类:帮助文档
【Linux】单机版QQ之管道中的命名管道 还记得上一篇的匿名管道吗? 文章目录 前言一、命名管道总结 前言 命名管道是什么呢? 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。 如果我们想在不相关的进程之间交换数据,可以使用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<0) { buffer[n] = 0; std::cout<<"client# "< #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); (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 总结 命名管道可用于同一主机上的任意进程间通信,并且管道通信的本质是通过内核中一块缓冲区(内存)时间数据传输,而命名管道的管道文件只是一个标识符,用于让多个进程能够访问同一块缓冲区,并且管道是半双工通信,是可以选择方向的单向通信。命名管道和匿名有一个相同点,就是他们的本质都是内核中的一块缓冲区。同时补充一点,管道的生命周期是随进程的,本质是内核中的缓冲区,命名管道文件只是标识,用于让多个进程找到同一块缓冲区,删除后,之前已经打开管道的进程依然可以通信。
香港云服务器租用推荐
服务器租用资讯
·广东云服务有限公司怎么样
·广东云服务器怎么样
·广东锐讯网络有限公司怎么样
·广东佛山的蜗牛怎么那么大
·广东单位电话主机号怎么填写
·管家婆 花生壳怎么用
·官网域名过期要怎么办
·官网邮箱一般怎么命名
·官网网站被篡改怎么办
服务器租用推荐
·美国服务器租用
·台湾服务器租用
·香港云服务器租用
·香港裸金属服务器
·香港高防服务器租用
·香港服务器租用特价