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

文章目录

序言

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

(所谓血缘关系就是上篇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到此结束,有用请三连~~

欢迎随时交流~~

相关推荐
华纳云IDC服务商1 分钟前
怎么选择香港服务器的线路?解决方案
服务器·网络·香港服务器
sss-web12267 分钟前
4.远程访问及控制
运维·服务器
EasyCVR26 分钟前
GA/T1400视图库平台EasyCVR视频融合平台HLS视频协议是什么?
服务器·网络·人工智能·音视频
moneyxjj27 分钟前
Linux各种解压命令汇总
linux·运维·服务器
白白♛~1 小时前
网络管理之---3种网络模式配置
linux·服务器·网络
GOTXX1 小时前
NAT、代理服务与内网穿透技术全解析
linux·网络·人工智能·计算机网络·智能路由器
脱了格子衬衫1 小时前
使用源码编译安装 Tomcat
linux·tomcat
陈yanyu1 小时前
Linux - 弯路系列3:安装和编译libvirt-4.5.0及虚拟网卡virbr0(virbr0-nic)创建
linux·运维·服务器
大风吹PP凉1 小时前
34Web服务器(如Apache, Nginx)
服务器·nginx·apache
feng68_1 小时前
Linux编辑/etc/fstab文件不当,不使用快照;进入救援模式
linux