解析命名管道:实现进程间通信的无名英雄

文章目录

序言

让无血缘关系的进程间通信

(所谓血缘关系就是上篇blog所讲的父子进程,子进程的子进程,父进程的两个子进程之间的关系等这种即为血缘关系).

linux中命名管道叫做fifo

利用指令创建

演示结果:

输出信息,实现通信

本来输出到次终端的信息,到了另一个终端

循环实现
echo和cat两个无相关的进程实现了通信

实现上述操作的时候再开一个终端发现,管道的大小一直是0

这个管道是创建出来的磁盘级的一个符号,实际通信不会向磁盘刷新,也没必要

命名管道本质

现在存在一个命名管道,A,B两个进程分别用读和写的方式打开,他俩看到了一份公共的资源

为什么能看到同一份资源?

路径具有唯一性,使用路径+文件名的方式,来唯一的让不同的进程看到同一份资源

现在A进程的实际执行情况是,打开了这个

文件,也有对应的文件缓冲区指向这个文件

B进程打开就不会再重新加载这个文件到

缓冲区之类的

但毕竟是不同的进程打开

他们各自进程指向的文件中的位置不一样

现在这个文件不是普通文件,而是mkfifo创建的管道文件,

所以此时文件不会指向对应的缓冲区,而是直接让两个进程在缓冲区进行交流

代码创建管道实现通信

makefifo创建命名管道文件

利用client和server两个进程来查看

bash 复制代码
.PHONY:all
all:server client

server:server.cc
	g++ -o $@ $^ -std=c++11
client:client.cc
	g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
	rm -f server client .fifo

通过代码在server创建管道

创建管道的发送服务端:

创建管道,创建失败返回错误信息

errno:向显示器输出错误信息(stderr)

strerror:strerror(errno): 接受错误码作为参数,并返回对应错误码的字符串描述

make生成

然后运行这个server服务创建管道:

read函数从指定文件中读取一个长度放回buf中,然回值是读取到的字符串的长度

读端代码(服务端)

写端代码(客户端)

最终两个.cc文件汇聚到一个.h内

为了让他们看到同一份资源

进行实践时,首先一定要打开读端,以前说过写端关闭,读端一直读,读端会读到文件的结尾,表示为0,即这时read的返回值为0.但是这里不会读到0,因为就要考虑这种情况,读端一直打开,写端没有时,会进行堵塞等待(个人猜测时mkfifo函数的功能导致阻塞),一定要先./server 然后再./client,再在./client端输入信息

这段代码是按下回车进行输出,通过这个例子可以通过某些函数接口实现实时信息输出(即按什么立刻显示什么,不用按回车)

上述代码不合理的地方,当fifo存在时会直接报错退出,现在实现不存在就创建,存在就不创建然后执行后续代码

完整代码

comm.h

cpp 复制代码
#include<iostream>
#include<unistd.h>
#include<vector>
#include<cstring>
#include<cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include<fcntl.h>
#define FIFONAME ".fifo"//生成的文件默认为隐藏文件
using namespace std;

server.cc

cpp 复制代码
#include "comm.h"
bool MakeFifo()
{
    int n = mkfifo(FIFONAME, 0666);//创建管道
    if(n < 0)
    {
        cerr << "errno:" << errno << ", errstring: " << strerror(errno) << endl;
        return false;
    }
    return true;
}
int main()
{
Strat:
    int rfd = open(FIFONAME,O_RDONLY);//打开管道
    if(rfd < 0)
    {
        if(MakeFifo()) goto Strat;
        cerr << "errno:" << errno << ", errstring: " << strerror(errno) << endl;
        return 1;
    }
    char buf[1024];
    while(true)//读端
    {
        ssize_t s = read(rfd,buf,sizeof(buf)-1);
        if(s > 0)
        {
            buf[s] = 0;
            cout << "Client say# " << buf << endl;
        }
        else if(s == 0)
        {
            cout << "client quit,server quit too!" << endl;
            break;
        }
    }

    close(rfd);
    return 0;
}

client.cc

cpp 复制代码
#include"comm.h"
int main()
{
    int wfd = open(FIFONAME,O_WRONLY);//打开管道文件
    if(wfd < 0)
    {
        cerr << "errno:" << errno << ", errstring: " << strerror(errno) << endl;
        return 1;
    }
    //将信息写入管道
    string message;
    while(true)
    {
        cout << "Please Enter# " << endl;
        getline(cin,message);//从键盘获取message
        
        //将message写入管道
        ssize_t s = write(wfd,message.c_str(),message.size());
        if(s < 0)
        {
            cerr << "errno:" << errno << ", errstring: " << strerror(errno) << endl;
            break;
        }


    }

    close(wfd);
    return 0;
}

本期blog到此结束,有用请三连~~

欢迎随时交流~~

相关推荐
闻缺陷则喜何志丹6 分钟前
【强连通分量 缩点 拓扑排序】P3387 【模板】缩点|普及+
c++·算法·拓扑排序·洛谷·强连通分量·缩点
搞Linux的杰仔25 分钟前
Ubuntu20.04基础配置安装——系统安装(一)
linux·嵌入式开发
hutaotaotao37 分钟前
c++中的输入输出流(标准IO,文件IO,字符串IO)
c++·io·fstream·sstream·iostream
AL流云。39 分钟前
【优选算法】C++滑动窗口
数据结构·c++·算法
qq_429879672 小时前
省略号和可变参数模板
开发语言·c++·算法
Kaede63 小时前
如何应对Linux云服务器磁盘空间不足的情况
linux·运维·服务器
CodeWithMe3 小时前
【C/C++】std::vector成员函数清单
开发语言·c++
uyeonashi3 小时前
【QT控件】输入类控件详解
开发语言·c++·qt
Zfox_5 小时前
Redis:Hash数据类型
服务器·数据库·redis·缓存·微服务·哈希算法
zh_xuan7 小时前
c++ 单例模式
开发语言·c++·单例模式