进程间通信-命名管道

目录

原理

代码 

简单通信

回归概念 


原理

mkfifo 是 Linux 系统中的一个命令,用于创建命名管道(named pipe),也称为 FIFO(First In, First Out)。命名管道是一种特殊类型的文件,用于进程间通信(IPC)。它允许一个进程将数据写入管道,而另一个进程可以从管道中读取这些数据。


创建一个命名管道文件(p);

pathname 是该函数的一个参数,用于指定要创建的命名管道的路径和文件名。这个路径可以是绝对路径或相对路径,具体取决于你的需求。

 当你使用 echo "i am i named fifo" > myfifo 命令时,它会被挂起,原因是 myfifo 是一个命名管道(FIFO)。命名管道需要有另一个进程从管道中读取数据,才能完成写入操作。如果没有其他进程读取 myfifo,echo 命令会被阻塞,直到有进程读取管道中的数据。

代码 

代码创建named pipe:

 删除named pipe:

在 C 语言中,unlink 函数用于删除文件或命名管道。它的功能是从文件系统中移除一个文件名,但并不立即删除文件数据直到所有引用该文件的数据描述符都被关闭。unlink 也可以用于删除一个命名管道(FIFO)


注意:
删除文件: unlink 只删除文件名,而不是立即删除文件数据。如果其他进程仍然打开该文件的描述符,文件数据将保持在磁盘上,直到所有文件描述符被关闭。
删除命名管道: 对于命名管道,unlink 删除的是管道的路径名,但不会立即影响正在使用该管道的进程。如果有进程正在读写该命名管道,管道本身的缓冲区不会立即被清除,直到所有打开的文件描述符关闭。

#pragma once
#include <iostream>
#include <string>
#include <cstdio>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

const std::string commpath = "./myfifo"; // 两个进程要通过共同的路径访问进程


int creatnamedpipe(const std::string &path)
{
    int res = mkfifo(path.c_str(), 0666); // 注意的是mkfifo要求的是c语言风格的字符串,所以用c_str(),默认文件权限
    if (res != 0)
    {
        perror("mkfifo"); // 管道创建失败会设置错误码
        // In the case of an error,-1 is returned (in which case, errno is set appropriately).
    }
    return res;
}
int removenamedpipe(const std::string &path)
{
    int res = unlink(path.c_str());
    if (res != 0)
    {
        perror("unlink"); // 移除失败会设置错误码
        //On error, -1 is returned, and errno is set appropriately.
    }
    return res;
}
#include"namedpipe.hpp"
//read
int main(){
    creatnamedpipe(commpath);
    sleep(5);
    removenamedpipe(commpath);
    return 0;
}

简单通信

serve.cc

#include "namedpipe.hpp"
// read
int main()
{
    namedpipe fifo(commpath, creater); // 告诉在哪里创建和身份
    //对于读端而言,如果我们打开文件但是写端还没来,我们可以打开但是我会阻塞在open调用中,直到对方打开;匿名管道不会存在这种情况
    //相当于变相的进程同步
    if (fifo.openforread())
    { // 打开成功
        while (true)
        {                        // 一直读
            std::string message; // 读的信息
            int n = fifo.readnamepipe(&message);
            if (n > 0)
            {
                std::cout << "client say : " << message << std::endl;
            }
            else if (n == 0)
            { // 对于读端来讲,如果写端关闭,读端再读就会读到零,代表读到文件结尾
                std::cout << " client quit, serve too ! " << std::endl;
                break;
            }
            else
            { // 出错了
                std::cout << "fifo.readnamepipe error " << std::endl;
                break;
            }
        }
    }
    return 0;
}

 client.cc

#include "namedpipe.hpp"
// write
int main()
{
    namedpipe fifo(commpath, user);
    if (fifo.openforwrite())
    { // 打开成功
    while(true){
        std::cout << "user write : ";
        std::string message; // 用户输入的message
        std::getline(std::cin, message);
        fifo.writenamepipe(message);
    }
    }
    return 0;
}

 namedpipe.hpp

#pragma once
#include <iostream>
#include <string>
#include <cstdio>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

const std::string commpath = "./myfifo"; // 两个进程要通过共同的路径访问进程

#define defaultfd -1
#define creater 1
#define user 2
#define Read O_RDONLY
#define Write O_WRONLY
#define basesize 1024 // 缓冲区默认

class namedpipe
{        // 用一个类来实现,不用函数了
private: // 不让外界看到基础的打开方式
    bool opennamedpipe(int mode)
    { // mode为打开文件的模式
        _fd = open(_fifo_path.c_str(), mode);
        if (_fd < 0)
        {
            return false;
        }
        return true;
    }

public:
    namedpipe(const std::string &path, int who) // 路径和名称,代表谁
        : _fifo_path(path), _id(who), _fd(defaultfd)
    {
        if (_id == 1)
        {                                               // 是创建者才能创建管道
            int res = mkfifo(_fifo_path.c_str(), 0666); // 注意的是mkfifo要求的是c语言风格的字符串,所以用c_str(),默认文件权限
            if (res != 0)
            {
                perror("mkfifo"); // 管道创建失败会设置错误码
                // In the case of an error,-1 is returned (in which case, errno is set appropriately).
            }
            std::cout << "creater cteat pipe " << std::endl;
        }
    }
    bool openforread()
    { // 打开读
        return opennamedpipe(Read);
    }
    bool openforwrite()
    { // 打开写
        return opennamedpipe(Write);
    }
    int readnamepipe(std::string *out)
    {                                              // 输出型
        char buffer[basesize];                     // 缓冲区,大小设置
        int n = read(_fd, buffer, sizeof(buffer)); // 读
        if (n > 0)
        {
            buffer[n] = 0;
            *out = buffer; // 带出去
        }
        return n;
    }
    int writenamepipe(const std::string &in)
    {                                      // 输入型
        return write(_fd, in.c_str(), in.size()); // 写
    }
    ~namedpipe()
    { // 析构
        if (_id == 1)
        { // 是创建者才能删除管道
            sleep(5);
            int res = unlink(_fifo_path.c_str());
            if (res != 0)
            {
                perror("unlink"); // 移除失败会设置错误码
                // On error, -1 is returned, and errno is set appropriately.
            }
            std::cout << "creater kill pipe " << std::endl;
        }
        if (_fd != defaultfd)
            close(_fd);
    }

private:
    const std::string _fifo_path;
    int _id; // 当前使用这个管道的人的身份
    int _fd; // 文件描述符
};

回归概念 

让不同的进程看到同一份资源------命名管道------通过文件路径

 如果vscode显示一直输入密码但是连接不上,可以试试这种方法;
可以了  是那个vscode-server文件有问题  有时候会出现垃圾数据导致不能连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangsir.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值