目录
原理
代码
简单通信
回归概念
原理
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文件有问题 有时候会出现垃圾数据导致不能连接