【Linux】IPC——命名管道(fifo)
【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查看文档)
核心代码:
#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(){// 正常的readwhile (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;
};