文章目录
- 1. 创建一个命名管道
- 2. 用命名管道实现server&client通信
- 2.0 log.hpp打印日志信息
- 2.1 comm.hpp(server.cc和client.cc共有文件)
- 2.2 server.cc读取数据
- 2.3 client.cc发送数据
- 2.4 结果展示
- 3. 还可以多个进程接收
1. 创建一个命名管道
-
命名管道可以从命令行上创建,命令行方法是使用下面这个命令。
$ mkfifo filename
上图可见进程间通信成功。 -
命名管道也可以从程序里创建,相关函数有
int mkfifo(const char *filename,mode_t mode);
查手册:
man 3 mkfifo
2. 用命名管道实现server&client通信
2.0 log.hpp打印日志信息
#ifndef _LOG_H_
#define _LOG_H_
#include <iostream>
#include <ctime>
enum e
{
Debug,
Notice,
Warning,
Error
};
const std::string msg[]{
"Debug",
"Notice",
"Warning",
"Error"};
std::ostream &log(std::string message, int level)
{
std::cout << " | " << (unsigned)time(nullptr) << " | " << msg[level] << " | " << message;
return std::cout;
}
#endif
2.1 comm.hpp(server.cc和client.cc共有文件)
#ifndef _COMM_H_
#define _COMM_H
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
#define MODE 0666
#define SIZE 128
string ipcpath = "./fifo.ioc";
#endif
2.2 server.cc读取数据
#include "comm.hpp"
#include "log.hpp"
int main()
{
// 1. 创建管道文件
if (mkfifo(ipcpath.c_str(), MODE) < 0)
{
perror("mkfifo");
exit(1);
}
log("创建管道文件成功", Debug) << " step 1" << endl;
// 2. 正常的文件操作
int fd = open(ipcpath.c_str(), O_RDONLY);
if (fd < 0)
{
perror("open");
exit(2);
}
log("打开管道文件成功", Debug) << " step 2" << endl;
// 3. 编写正常代码
char buffer[SIZE];
while (true)
{
ssize_t s = read(fd, buffer, sizeof(buffer) - 1);
if (s > 0)
{
cout << "[" << getpid() << "]"
<< "client say " << buffer << endl;
}
else if (s == 0)
{
// end of file
cerr << "[" << getpid() << "]"
<< "read end of file, client quit, server quit too!" << endl;
break;
}
else
{
// read error
perror("read");
exit(3);
break;
}
}
// 4. 关闭文件
close(fd);
log("关闭管道文件成功", Debug) << " step 3" << endl;
unlink(ipcpath.c_str()); //通信完毕,就删除文件
log("删除管道文件成功", Debug) << " step 4" << endl;
return 0;
}
2.3 client.cc发送数据
#include "comm.hpp"
int main()
{
// 1. 获取管道文件
int fd = open(ipcpath.c_str(), O_WRONLY);
if (fd < 0)
{
perror("open");
exit(1);
}
// 2. ipc过程
string buffer;
while (true)
{
cout << "请输入一行信息 :> ";
getline(cin, buffer);
write(fd, buffer.c_str(), buffer.size());
}
// 3. 关闭
close(fd);
return 0;
}
2.4 结果展示
3. 还可以多个进程接收
- client.cc
#include "comm.hpp"
#include "log.hpp"
#include <sys/wait.h>
static void getMessag(int fd)
{
char buffer[SIZE];
while (true)
{
ssize_t s = read(fd, buffer, sizeof(buffer) - 1);
if (s > 0)
{
cout << "[" << getpid() << "]"
<< "client say " << buffer << endl;
}
else if (s == 0)
{
// end of file
cerr << "[" << getpid() << "]"
<< "read end of file, client quit, server quit too!" << endl;
break;
}
else
{
// read error
perror("read");
exit(3);
break;
}
}
}
int main()
{
// 1. 创建管道文件
if (mkfifo(ipcpath.c_str(), MODE) < 0)
{
perror("mkfifo");
exit(1);
}
log("创建管道文件成功", Debug) << " step 1" << endl;
// 2. 正常的文件操作
int fd = open(ipcpath.c_str(), O_RDONLY);
if (fd < 0)
{
perror("open");
exit(2);
}
log("打开管道文件成功", Debug) << " step 2" << endl;
for (int i = 0; i < 3; i++)
{
pid_t id = fork();
if (id == 0)
{
// 3. 编写正常代码
getMessag(fd);
exit(0);
}
}
for (int i = 0; i < 3; i++)
{
waitpid(-1, nullptr, 0);
}
// 4. 关闭文件
close(fd);
log("关闭管道文件成功", Debug) << " step 3" << endl;
unlink(ipcpath.c_str()); //通信完毕,就删除文件
log("删除管道文件成功", Debug) << " step 4" << endl;
return 0;
}