【Linux】IPC------命名管道(fifo)
完整代码码云:间尺/review
实现利用fifo让两个进程进行通信,再次基础上完成客户端和服务端半双工通信的功能。
ps:这里的fifo可不是(first in first out),只是名字一样罢了。
fifo和pipe
两者都是内存级的
特性 | 匿名管道 (PIPE) | 命名管道 (FIFO) |
---|---|---|
进程关系 | 必须有亲缘关系 | 任意进程都可访问 |
文件系统 | 不可见 | 在文件系统中可见(ls 命令可以看到创建的FIFO) |
创建方式 | pipe() 系统调用 |
mkfifo() 函数或命令 |
持久性 | 随进程结束 | 持久化直到被删除 |
使用场景 | 父子进程通信 | 任意进程间通信 |
fifo
本质上和pipe
相同,都是再内存上创建管道文件,fifo
管道文件可以通过文件系统找到,在使用中,和文件操作相同。
代码
-
指令:
mkfifo fifo
创建fifo
管道文件,ll
查看文件属性,发现第一个属性是p
,意味他就是管道文件。unlink fifo
可以删除管道文件。 -
系统调用:
mkfifo
unlink
(自行man 3查看文档)
核心代码:
c++
#pragma once
#include <iostream>
#include <cstdio>
#include <string>
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define PATH "."
#define FILENAME "fifo"
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
class NamedFifo
{
public:
NamedFifo(const std::string &path, const std::string &name)
: _path(path), _name(name)
{
_fifoname = _path + "/" + _name;
umask(0);
// 新建管道
int n = mkfifo(_fifoname.c_str(), 0666);
if (n < 0)
{
ERR_EXIT("mkfifo");
}
else
{
std::cout << "mkfifo success" << std::endl;
}
}
~NamedFifo()
{
// 删除管道文件
int n = unlink(_fifoname.c_str());
if (n == 0)
{
ERR_EXIT("unlink");
}
else
{
std::cout << "remove fifo failed" << std::endl;
}
}
private:
std::string _path;
std::string _name;
std::string _fifoname;
};
class FileOper
{
public:
FileOper(const std::string &path, const std::string &name)
: _path(path), _name(name), _fd(-1)
{
_fifoname = _path + "/" + _name;
}
void OpenForRead()
{
// 打开, write 方没有执行open的时候,read方,就要在open内部进行阻塞
// 直到有人把管道文件打开了,open才会返回!
_fd = open(_fifoname.c_str(), O_RDONLY);
if (_fd < 0)
{
ERR_EXIT("open");
}
std::cout << "open fifo success" << std::endl;
}
void OpenForWrite()
{
// write
_fd = open(_fifoname.c_str(), O_WRONLY);
if (_fd < 0)
{
ERR_EXIT("open");
}
std::cout << "open fifo success" << std::endl;
}
void Write()
{
// 写入操作
std::string message;
int cnt = 1;
pid_t id = getpid();
while (true)
{
std::cout << "Please Enter# ";
std::getline(std::cin, message);
message += (", message number: " + std::to_string(cnt++) + ", [" + std::to_string(id) + "]");
write(_fd, message.c_str(), message.size());
}
}
void Read()
{
// 正常的read
while (true)
{
char buffer[1024];
int number = read(_fd, buffer, sizeof(buffer) - 1);
if (number > 0)
{
buffer[number] = 0;
std::cout << "Client Say# " << buffer << std::endl;
}
else if (number == 0)
{
std::cout << "client quit! me too!" << std::endl;
break;
}
else
{
std::cerr << "read error" << std::endl;
break;
}
}
}
void Close()
{
if (_fd > 0)
close(_fd);
}
~FileOper()
{
}
private:
std::string _path;
std::string _name;
std::string _fifoname;
int _fd;
};
运行结果
