📟作者主页:慢热的陕西人
🌴专栏链接:Linux
📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言
本博客主要内容讲解了什么是命名管道,匿名管道和命名管道的区别,并且实现了一个案例来实践操作
文章目录
- Linux命名管道
- 1.概念
- 2.创建一个命名管道
- 3.匿名管道与命名管道的区别
- 4.我们实现一个即时的输入输出
- 5.完整代码
Linux命名管道
1.概念
- 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信
- 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道
- 命名管道是一种特殊类型的文件
2.创建一个命名管道
命名管道可以从命令行上创建,命令行方法是使用下面这个命令 :
mkfifo filename
见见猪跑:
向管道写入:
echo hello > fifo
:我们发现程序卡住了,细节是我们查看fifo的文件的大小的时候,它却是0,因为我们知道管道是内存级文件,他的内容不会刷新到磁盘,所以我们看到的文件大小就是0,当我们cat < fifo
也就是将fifo中的内容重定向输出到cat中打印出了hello
。
那么上面的操作,是通过一个管道文件,让两个无关的进程实现的进程间的通信。那么我们知道进程间的通信就是要让两个进程看到同一个文件,那么这里我们是如何做到同一个文件呢?答案是路径,文件的唯一性就是由路径表示的!
那么我们到底是如何使用命名管道实现两个进程间的通信的:
①我们需要创建一个管道文件
这里我们需要用到一个系统接口
mkfifo
#include<iostream> #include<sys/stat.h> #include<sys/types.h> #include<string.h> #include<cerrno>#include "comm.hpp"using namespace std; int main() { //1.创建管道文件,我们今天只需要创建一次 int n = mkfifo(filename.c_str(),mode); if(n != 0) //创建失败 {cout << errno << " : "<< strerror(errno)<< endl;return 1; }return 0; }
运行一下:
我们发现确实创建了文件:但是文件的权限却不是我们想要的
0666
,其实我们一下就能看出来原因是我们的umask
不为零影响到了结果我们查看一个操作系统的接口:
umask
#include<iostream> #include<sys/stat.h> #include<sys/types.h> #include<string.h> #include<cerrno>#include "comm.hpp"using namespace std; int main() { //1.创建管道文件,我们今天只需要创建一次 umask(0); //只影响当前进程的umask int n = mkfifo(filename.c_str(),mode); if(n != 0) //创建失败 {cout << errno << " : "<< strerror(errno)<< endl;return 1; }return 0; }
运行一下看看:
②让读写端进程分别按照自己的需求打开文件
//1.不需要创建管道文件,我只需要打开对应的文件即可!int wfd = open(filename.c_str(), O_WRONLY);if(wfd < 0){cerr << errno << " : "<< strerror(errno)<< endl;return 1;}//1.创建管道文件,我们今天只需要创建一次umask(0); //只影响当前进程的umaskint n = mkfifo(filename.c_str(),mode);if(n != 0) //创建失败{cout << errno << " : "<< strerror(errno)<< endl;return 1;}
③开始通信
//3.开始通信char buffer[NUM];while(true){buffer[0] = 0; //初始化第一个位置为\0//读文件ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);if(n > 0){//读成功了buffer[n] = 0;printf("%s\n", buffer);fflush(stdout);}else if(n == 0){//写端关闭cout << "client quit, me too" << endl;break;}else{//错误cout << errno << " : "<< strerror(errno)<< endl;return 1;}}//2.开始通信char buffer[NUM];while(true){cout << "请输入要写入的信息#";char* msg = fgets(buffer, sizeof(buffer), stdin);assert(msg);(void)msg;buffer[strlen(buffer) - 1] = 0;//当我们写入quit的时候退出写端if(strcasecmp(buffer, "quit") == 0) break;ssize_t n = write(wfd, buffer, strlen(buffer));assert(n >= 0); (void)n;}
运行结果:
3.匿名管道与命名管道的区别
- 匿名管道由pipe函数创建并打开。
- 命名管道由mkfifo函数创建,打开用open
- FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义
4.我们实现一个即时的输入输出
就是我们输入管道的时候不用回车,而是选用输入一个字符就从管道输出:
我们要在client.cc
端改变其向文件写入的方式,我们读取到字符c中,然后没输入一个字符就同步;
while(true){system("stty raw"); // 使终端驱动处于一次一字符模式char c = getchar();system("stty cooked");// 使终端驱动回到一次一行模式 ssize_t n = write(wfd, &c, sizeof(char));assert(n >= 0); (void)n;}
运行结果:
5.完整代码
client.cc
#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<cerrno>
#include<cassert>
#include"comm.hpp"using namespace std;
int main()
{//1.不需要创建管道文件,我只需要打开对应的文件即可!int wfd = open(filename.c_str(), O_WRONLY);if(wfd < 0){cerr << errno << " : "<< strerror(errno)<< endl;return 1;}//2.开始通信char buffer[NUM];while(true){// cout << "请输入要写入的信息#";// char* msg = fgets(buffer, sizeof(buffer), stdin);// assert(msg);// (void)msg;// buffer[strlen(buffer) - 1] = 0;system("stty raw"); // 使终端驱动处于一次一字符模式char c = getchar();system("stty cooked");// 使终端驱动回到一次一行模式 // //当我们写入quit的时候退出写端// if(strcasecmp(buffer, "quit") == 0) break;ssize_t n = write(wfd, &c, sizeof(char));assert(n >= 0); (void)n;}return 0;
}
server.cc
#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<cerrno>#include "comm.hpp"using namespace std;
int main()
{//1.创建管道文件,我们今天只需要创建一次umask(0); //只影响当前进程的umaskint n = mkfifo(filename.c_str(),mode);if(n != 0) //创建失败{cout << errno << " : "<< strerror(errno)<< endl;return 1;}cout << "创建文件成功!"<< endl;//2.打开文件int rfd = open(filename.c_str(), O_RDONLY);if(rfd < 0) //打开错误{cout << errno << " : "<< strerror(errno)<< endl;return 2;}cout << "打开管道成功" << endl;//3.开始通信char buffer[NUM];while(true){buffer[0] = 0; //初始化第一个位置为\0//读文件ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);if(n > 0){//读成功了printf("%c", buffer[0]);fflush(stdout);}else if(n == 0){//写端关闭cout << "client quit, me too" << endl;break;}else{//错误cout << errno << " : "<< strerror(errno)<< endl;return 1;}}//4.关闭文件close(rfd);unlink(filename.c_str());return 0;
}
comm.hpp
#pragma once#include <iostream>
#include <string>using namespace std;#define NUM 65535 //管道缓冲区大小string filename = "./fifo"; //文件名
mode_t mode = 0666; //打开方式
到这本篇博客的内容就到此结束了。
如果觉得本篇博客内容对你有所帮助的话,可以点赞,收藏,顺便关注一下!
如果文章内容有错误,欢迎在评论区指正