匿名管道和命名管道的概述理解(笔记版)




匿名管道的c++实现:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <cassert>
#include <vector>
#include <unordered_map>
#include <fcntl.h>
using namespace std;
typedef void (*funcs)();
vector<funcs> functor;
// 调试信息
unordered_map<uint32_t, string> info;
void func1()
{
cout << "这是一个处理日志的任务, 执行的进程 ID [" << getpid() << "]"
<< "执行时间是[" << time(nullptr) << "]\n"
<< endl;
}
void func2()
{
cout << "这是一个备份数据的任务, 执行的进程 ID [" << getpid() << "]"
<< "执行时间是[" << time(nullptr) << "]\n"
<< endl;
}
void func3()
{
cout << "这是一个网络连接的任务, 执行的进程 ID [" << getpid() << "]"
<< "执行时间是[" << time(nullptr) << "]\n"
<< endl;
}
void loadTask()
{
info.insert(make_pair(functor.size(), "处理日志"));
functor.push_back(func1);
info.insert(make_pair(functor.size(), "备份数据"));
functor.push_back(func2);
info.insert(make_pair(functor.size(), "网路连接"));
functor.push_back(func3);
}
//<子进程的pid,该子进程对应的写端>
typedef pair<uint32_t, uint32_t> elem;
int processNum = 5;
void work(int blocks)
{
cout << "进程[" << getpid() << "]"
<< " 开始工作" << endl;
while (true)
{
uint32_t operatorCode = 0;
ssize_t s = read(blocks, &operatorCode, sizeof(uint32_t));
if (s == 0)
break;
assert(s == sizeof(uint32_t));
(void)s;
if (operatorCode < functor.size())
functor[operatorCode]();
}
cout << "进程[" << getpid() << "]"
<< " 结束工作" << endl;
}
void balanceSendTask(const vector<elem> &processFds)
{
srand((long long)time(nullptr));
while (true)
{
sleep(1);
// 选择一个进程, 选择进程是随机的,没有压着一个进程给任务
// 较为均匀的将任务给所有的子进程 --- 负载均衡
uint32_t process = rand() % processFds.size();
uint32_t task = rand() % functor.size();
write(processFds[process].second, &task, sizeof(uint32_t));
cout << "父进程指派任务->" << info[task] << "给进程: " << processFds[process].first << " 编号: " << process << endl;
}
}
// 父进程控制一批子进程通信(进程池)
int main()
{
info.insert(make_pair(functor.size(), "处理日志"));
functor.push_back(func1);
info.insert(make_pair(functor.size(), "备份数据"));
functor.push_back(func2);
info.insert(make_pair(functor.size(), "网路连接"));
functor.push_back(func3);
vector<elem> assignTask;
// 循环创建子进程
for (size_t i = 0; i < processNum; i++)
{
int pipefd[2] = {0};
if (pipe(pipefd) < 0)
{
cerr << "pipe error" << endl;
return 1;
}
pid_t id = fork();
if (id < 0)
{
cerr << "fork error" << endl;
}
else if (id == 0)
{
close(pipefd[1]);
work(pipefd[0]);
close(pipefd[0]);
exit(0);
}
else
{
close(pipefd[0]);
elem e(id, pipefd[1]);
assignTask.push_back(e);
}
}
balanceSendTask(assignTask);
for (size_t i = 0; i < processNum; i++)
{
int res = waitpid(assignTask[i].first, nullptr, 0);
if (res)
{
cout << "wait " << assignTask[i].first << " success" << endl;
}
}
return 0;
}
// 父进程控制子进程通信
// int main()
// {
// info.insert(make_pair(functor.size(), "处理日志"));
// functor.push_back(func1);
// info.insert(make_pair(functor.size(), "备份数据"));
// functor.push_back(func2);
// info.insert(make_pair(functor.size(), "网路连接"));
// functor.push_back(func3);
// int pipefd[2] = {0};
// if (pipe(pipefd) < 0)
// {
// cerr << "pipe error" << endl;
// return 1;
// }
// pid_t id = fork();
// if (id < 0)
// {
// cerr << "fork error" << endl;
// return 2;
// }
// else if (id == 0)
// {
// close(pipefd[1]);
// while (true)
// {
// uint32_t operatorTask = 0;
// // 希望读取sizeof(operatorTask)个字符到operatorTask(void *__buf)中,实际读取s个字符,
// ssize_t s = read(pipefd[0], &operatorTask, sizeof(uint32_t));
// if (s == 0)
// {
// cout << "父进程退出了,我也退出了" << endl;
// break;
// }
// assert(s == sizeof(uint32_t));
// // assert断言 在debug模式是编译有效
// // release模式,断言就没有了;
// // 一旦断言没有了,s变量就是只被定义了,没有被使用。
// // release模式中,可能会有warning
// (void)s;
// if (operatorTask < functor.size())
// {
// functor[operatorTask]();
// }
// else
// {
// cerr << "bug? operatorTask = " << operatorTask << endl;
// }
// }
// close(pipefd[0]);
// exit(0);
// }
// else
// {
// close(pipefd[0]);
// srand((long long)time(nullptr));
// int num = functor.size();
// int cnt = 10;
// while (cnt--)
// {
// uint32_t assignTask = rand() % num;
// cout << "父进程指派的任务是:" << info[assignTask] << ",编号是:" << cnt << endl;
// write(pipefd[1], &assignTask, sizeof(uint32_t));
// sleep(1);
// }
// close(pipefd[1]);
// pid_t res = waitpid(id, nullptr, 0);
// if (res > 0)
// cout << "wait success" << endl;
// }
// return 0;
// }
// pipe基本通信的过程
// int main()
// {
// int pipe_fd[2] = {0};
// if (pipe(pipe_fd) != 0)
// {
// cerr << "pipe error" << endl;
// return 1;
// }
// pid_t pid = fork();
// if (pid < 0)
// {
// cerr << "fork error" << endl;
// return 2;
// }
// else if (pid == 0)
// {
// close(pipe_fd[1]);
// char buffer[1024];
// while (1)
// {
// memset(buffer, 0, sizeof(buffer));
// ssize_t r = read(pipe_fd[0], buffer, sizeof(buffer) - 1);
// if (r > 0)
// {
// buffer[r] = '\0';
// cout << "子进程读取成功," << buffer << endl;
// }
// else if (r == 0)
// {
// cout << "父进程写完了,子进程也退出了" << endl;
// break;
// }
// }
// close(pipe_fd[0]);
// exit(0);
// }
// else
// {
// close(pipe_fd[0]);
// const char *meg = "你好子进程,我是父进程, 这次发送的信息编号是: ";
// int cnt = 0;
// while (cnt < 5)
// {
// char spearBuffer[1024];
// sprintf(spearBuffer, "%s %d", meg, cnt);
// sleep(3);
// write(pipe_fd[1], spearBuffer, sizeof(spearBuffer));
// cnt++;
// }
// close(pipe_fd[1]);
// cout << "父进程写完了" << endl;
// }
// pid_t res = waitpid(pid, 0, 1);
// if (res > 0)
// {
// cout << "等待子进程成功" << endl;
// }
// return 0;
// }
命名管道的c++实现:
common.h头文件:
#pragma once
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define IPC_PATH "./.fifo"
serverFifo.cpp:
// 读取
#include "common.h"
using namespace std;
int main()
{
umask(0);
if (mkfifo(IPC_PATH, 0600) != 0)
{
cerr << "mkfifo error" << endl;
return 1;
}
int pipeFd = open(IPC_PATH, O_RDONLY);
if (pipeFd < 0)
{
cerr << "open fifo error" << endl;
return 2;
}
#define NUM 1024
// 正常的通信过程
char buffer[NUM];
while (true)
{
ssize_t s = read(pipeFd, buffer, sizeof(buffer) - 1);
if (s > 0)
{
buffer[s] = '\0';
cout << "客户端->服务器# " << buffer << endl;
}
else if (s == 0)
{
cout << "客户退出啦,我也退出把";
break;
}
else
{
// do nothing
cout << "read: " << strerror(errno) << endl;
break;
}
}
close(pipeFd);
cout << "服务端退出啦" << endl;
unlink(IPC_PATH);
return 0;
}
clientFifo.cpp:
// 写入
#include "common.h"
using namespace std;
int main()
{
int pipeFd = open(IPC_PATH, O_WRONLY);
if (pipeFd < 0)
{
cerr << "open: " << strerror(errno) << endl;
return 1;
}
#define NUM 1024
char line[NUM];
while (true)
{
printf("请输入你的消息# ");
fflush(stdout);
memset(line, 0, sizeof(line));
// fgets -> C -> line结尾自动添加\0
if (fgets(line, sizeof(line), stdin) != nullptr)
{
// abcd\n\0
line[strlen(line) - 1] = '\0';
write(pipeFd, line, strlen(line));
}
else
{
break;
}
}
close(pipeFd);
cout << "客户端退出啦" << endl;
return 0;
}