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

文章目录

序言

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

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

欢迎随时交流~~

相关推荐
lijiachang0307184 分钟前
设计模式(一):单例模式
c++·笔记·学习·程序人生·单例模式·设计模式·大学生
<但凡.7 分钟前
题海拾贝:蓝桥杯 2020 省AB 乘法表
c++·算法·蓝桥杯
hc_bmxxf11 分钟前
Linux应用软件编程-多任务处理(进程)
linux·运维·服务器
DogDaoDao31 分钟前
leetcode 面试经典 150 题:矩阵置零
数据结构·c++·leetcode·面试·矩阵·二维数组·矩阵置零
M-C-B33 分钟前
配置带外与更改密码
运维·服务器
沐多40 分钟前
波折重重:一个Linux实时系统Xenomai宕机问题的深度定位过程
linux·xenomai·实时linux·xenomai4
猿经验44 分钟前
tar.gz压缩文件在linux上解压异常问题:gzip:stdin:invalid compressed data
linux·运维·服务器
木卫二号Coding1 小时前
宝塔-firefox(Docker应用)-构建自己的Web浏览器
linux·docker·开源
SP八岐大兔1 小时前
Linux(Ubuntu/CentOS)配置开机自启动服务
linux·ubuntu·centos
玄德公笔记1 小时前
docker-compose搭建sfpt服务器
服务器·docker·容器·sftp·docker-compose