This commit is contained in:
qing committed 2026-07-20 11:12:29 +08:00
commit 70d467d052
97 files changed
+10386

No files matched your search

+177
View File
@@ -0,0 +1,177 @@
//作者:简单
//修改:qing
/*
* C++17支持了中文变量名,配合define预编译指令可以将代码中文化。
*
* 在C语言中,变量名只能由字母、数字或是下划线组成。
* 由于C++语言兼容C语言,最开始的C++是不能够使用多字节变量名的。
*
* */
#ifndef __中文模式
#define __中文模式
#include <stdint.h>
/*保留字*/
#define 使用 using
#define 命名空间 namespace
#define 取别名 typedef
#define 覆盖 override
#define 取内存大小 sizeof
#define 返回 return
#define 如果 if
#define 否则 else
#define 又或者 else if
#define 真 true
#define 假 false
//#define 且 and
//#define 或 or
#define 空类型 void
#define 常量 const
#define 有符号 signed
#define 无符号 unsigned
#define 文件 FILE
#define 文件结束 EOF
#define 类 class
#define 结构体 struct
#define 枚举类型 enum
#define 对象 this
#define 抛出异常 throw
#define 新建 new
//#define 新的 new
#define 删除 delete
#define 跳出 break
#define 继续 continue
#define 判断循环 while
#define 循环判断 do
#define 循环判断尾 while
#define 分支选择 switch
#define 支系 case
#define 缺省 default
#define 计次循环 for
#define 尝试 try
#define 获取异常 catch
#define 捕获异常 catch
#define 退出 exit
#define 公开的 public
#define 受保护的 protected
#define 私有的 private
#define 外部的 extern
#define 静态的 static
#define 虚拟的 virtual
#define 有号8位整 int8_t
#define 无号8位整 uint8_t
#define 有号16位整 int16_t
#define 无号16位整 uint16_t
#define 有号32位整 int32_t
#define 无号32位整 uint32_t
#define 有号64位整 int64_t
#define 无号64位整 uint64_t
#define 空的 NULL
#define 空指针 nullptr
#define 整数 int
#define 字符 char
#define 短整数 short
#define 长型 long
#define 超长型 long long
#define 单精度小数 float
#define 双精度小数 double
#define 长度单位 size_t
#define 布尔 bool
#define 逻辑型 bool
#define 可变类型 auto
#define 自动的 auto
#define 适应 auto
#define _文件 FILE
#define _文件结束 EOF
#define _读模式 "r"
#define _写模式 "w"
#define 模板 template
#define 类型名 typename
#define 默认的 default
#define 被删除 delete
#define 入口 main
#define 主函数 main
#define 或 ||
#define 或者 ||
#define 而且 &&
#define 且 &&
#define 等于 ==
#define 大于等于 >=
#define 小于等于 <=
#define 大于 >
#define 小于 <
#define 不报错的 noexcept
#define 不转换的 explicit
#define 纯函数的 consteval
#define 预求值的 constexpr
#define _加法重载 operator+
#define _取下标重载 operator[]
#define _开始 begin
#define _结束 end
//-----------------------------------------------------------
//-----------------------------------------------------------
//基本单元
#ifdef __cplusplus
#include <iostream>
命名空间 中文标准{
类 字符串 {
公开的:
/* 初始化为空字符串 */
字符串() {
对象->s = "";
}
/* 以字面量初始化 */
字符串(常量 字符* 源) {
对象->s = 源;
}
/* 访问器 */
常量 字符* 取值() {
返回 s.c_str();
}
/* */
字符串& _加法重载(常量 字符* 乙方) {
对象->s += 乙方;
返回 *对象;
}
/* 字符串之间的连接 */
字符串& _加法重载(字符串& 乙) {
对象->s += 乙.取值();
返回 *对象;
}
私有的:
std::string s;
};
类 标准输出{
公开的:
空类型 调试输出(常量 字符* 消息) {
std::cout << 消息;
}
空类型 调试输出(字符串& 信) {
std::cout<< 信.取值();
}
};
类 标准输入{
公开的:
字符串 取字符串(){
std::string s;
std::cin >> s;
返回 字符串(s.c_str());
}
整数 取整数() {
整数 数;
std::cin >> 数;
返回 数;
}
};
}
#endif //__cplusplus
#endif //__中文模式
+129
View File
@@ -0,0 +1,129 @@
#pragma once
#include "中文化.hpp"
#include "异常.hpp"
命名空间 中文标准 {
模板 <类型名 类型1>
类 向量{
公开的:
/* 注意:当长度单位为0时,内部指针是空的 */
向量() {
对象->指针 = 空指针;
对象->容量 = 0;
}
/* 专门用于处理花括号初始化列表 */
向量(常量 std::initializer_list<类型1>& init = {}) {
对象->指针 = 新建 类型1[init.size()] {空的};
对象->容量 = init.size();
长度单位 计数 = 0;
计次循环(适应 & 东西: init) {
对象->指针[计数++] = 东西;
}
}
~向量() {
删除 对象->指针;
对象->指针 = 空指针;
对象->容量 = 0;
}
/*----------访问器----------*/
长度单位 取容量() {
返回 对象->容量;
}
布尔 是否为空() {
返回 对象->容量 等于 0;
}
/*--------运算符重载--------*/
向量& _取下标重载( 常量 长度单位 下标 ) {
如果(下标 < 0 或 下标 >= 对象->容量)
抛出异常 下标越界{"向量", 对象->容量, 下标};
返回 对象->指针[下标];
}
/*--------可范围遍历--------*/
类型1* _开始() {
返回 对象->指针;
}
类型1* _结束() {
返回 对象->指针 + 对象->容量;
}
/*----------变异器----------*/
空类型 插入元素(常量 长度单位 位置, 常量 向量& 媒介) {
/* 越界检查 */
如果(位置 < 0 或 位置 > 对象->容量)
抛出异常 下标越界{"向量元素插入", 对象->容量+1, 位置};
适应 长度 = 取容量();
适应 新的 = 新建 类型1[长度 + 1] { 空的 };
/* 插入位置之前 */
计次循环(适应 计数 = 0; 计数 < 位置; ++计数)
新的[计数] = 对象->指针[计数];
/* 执行插入 */
新的[位置] = 媒介;
/* 插入位置之后 */
计次循环(适应 计数 = 位置 + 1; 计数 <= 长度; ++计数)
新的[计数] = 对象->指针[计数 - 1];
如果(对象->指针) 删除[] 对象->指针; /* 可能为空 */
对象->指针 = 新的;
}
空类型 追加元素(常量 向量& 媒介) {
适应 长度 = 取容量();
适应 新的 = 新建 类型1[长度 +1] {空的};
计次循环(适应 计数 = 0; 计数 < 长度; ++计数)
新的[计数] = 对象->指针[计数];
新的[长度] = 媒介;
如果(对象->指针) 删除[] 指针; /* 可能为空 */
对象->指针 = 新的;
}
空类型 删除元素(常量 长度单位 位置) {
/* 越界检查 */
如果(位置 < 0 或 位置 >= 对象->容量)
抛出异常 下标越界{"向量元素插入", 对象->容量 + 1, 位置};
适应 长度 = 取容量();
适应 新的 = (长度 等于 1)
? 空指针 : 新建 类型1[长度 - 1] { 空的 };
/* 目标位置之前 */
计次循环(适应 计数 = 0; 计数 < 位置; ++计数)
新的[计数] = 对象->指针[计数];
/* 目标位置之后 */
计次循环(适应 计数 = 位置; 计数 < 长度; ++计数)
新的[计数] = 对象->指针[计数 + 1];
删除[] 对象->指针;
对象->指针 = 新的;
}
/*----------------*/
//类 迭代器{
//公开的:
// 迭代器(常量 std::vector<类型1>::iterator& it) {
// this->it = it;
// }
//私有的:
// std::vector<类型1>::iterator it;
//};
/*----------------*/
私有的:
类型1 *指针;
长度单位 容量;
};
}
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include "中文化.hpp"
命名空间 中文标准 {
类 标准异常 : 公开的 std::exception {
公开的:
不转换的 标准异常(常量 字符* 信息): 信息(信息) {}
常量 字符* what() 常量 不报错的 覆盖 {
返回 信息;
}
私有的:
常量 字符* 信息;
};
类 下标越界 : 公开的 标准异常{
公开的:
下标越界(常量 字符 * 提示, 常量 长度单位 标准值, 常量 长度单位 目前值)
: 标准异常(提示), 标准值(标准值), 目前值(目前值) {
};
长度单位 取标准值() { 返回 标准值; }
长度单位 取目前值() { 返回 目前值; }
私有的:
长度单位 标准值, 目前值;
};
}
+97
View File
@@ -0,0 +1,97 @@
#pragma once
#include "中文化.hpp"
#include "异常.hpp"
#include "顺序表.hpp"
命名空间 中文标准 {
模板 <类型名 类型1, 长度单位 节点大小 = 64>
类 链串 {
公开的:
/* 初始化为空链串 */
链串() {
对象->长度 = 0;
对象->下一个 = 空指针;
对象->上一个 = 空指针;
对象->头 = 对象; /* 每一个子节点都记录同一个头结点 */
对象->尾 = 对象; /* 为了方便,只有头结点记录尾节点 */
}
链串 (常量 std::initializer_list<类型1>& init = {})
{
计次循环(适应 & 东西: init) {
插入(东西);
}
}
/*
* 链式析构
*
* 析构时,会递归析构所有节点。
*/
~链串() {
删除[] 对象->下一个;
}
空类型 插入(常量 类型1& 元素) {
链串 *暂时 = 对象->尾;
如果(暂时->长度 等于 节点大小)
_推();
暂时->存储[暂时->长度++] = 元素;
}
长度单位 统计() {
长度单位 总数 = 0;
链串 *暂时 = 对象->头;
判断循环(暂时 != 空指针) {
总数 += 暂时->长度;
暂时 = 暂时->下一个;
}
返回 总数;
}
/*
* 链串重组
*
* 将链串重组为顺序表W
*/
顺序表<类型1> 重组() {
顺序表<类型1> 结果(统计());
链串 *暂时 = 对象->头;
长度单位 计数 = 0;
判断循环(暂时 != 空指针) {
计次循环(适应 索引 = 0; 索引 < 暂时->长度; ++索引) {
结果[计数++] = 暂时->存储[索引];
}
暂时 = 暂时->下一个;
}
返回 结果;
}
类 链串异常: 公开的 标准异常{
公开的:
链串异常(常量 字符* 消息) : 标准异常(消息) {}
};
私有的:
类型1 存储[节点大小];
长度单位 长度; /* 存储中的元素数量 */
链串 *下一个;
链串 *上一个;
链串 *头;
链串 *尾;
空类型 _推() {
链串*新的;
尝试{ 新的 = 新建 链串(); }
捕获异常 (std::exception& exp){
抛出异常 链串异常{"链串推失败"};
}
_拼接节点(新的);
}
空类型 _拼接节点(链串* 新的) {
对象->尾->下一个 = 新的;
新的->上一个 = 对象->尾;
对象->尾 = 新的;
新的->头 = 对象;
}
};
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include "中文化.hpp"
#include "异常.hpp"
命名空间 中文标准 {
模板<类型名 类型1>
类 顺序表 {
公开的:
顺序表(长度单位 大小) {
存储 = 新建 类型1[大小];
长度 = 大小;
}
~顺序表() {
删除[] 存储;
}
类型1 _取下标重载(长度单位 下标) {
如果(下标 >= 长度)
抛出异常 顺序表异常{"下标超出范围"};
返回 存储[下标];
}
类 顺序表异常: 公开的 标准异常{
公开的:
顺序表异常(常量 字符* 消息) : 标准异常(消息) {}
};
私有的:
类型1 *存储;
长度单位 长度;
};
}
+107
View File
@@ -0,0 +1,107 @@
/* 日志 */
#pragma once
#include <iostream>
#include <string>
#include <mutex>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <ctime>
enum class LogLevel {
DEBUG,
INFO,
WARNING,
ERROR,
CRITICAL
};
namespace qing {
/*
* 这是由Deepseek创作的,用于记录日志的类模块
* 简化版本,只输出到控制台
*
* 优化意见:改为存储日志文件
*/
class Logger {
public:
//获取日志实例(单例模式)
static Logger& getInstance() {
static Logger instance;
return instance;
}
//初始化日志系统
void init(LogLevel minLogLevel = LogLevel::INFO,
bool consoleOutput = true) {
std::lock_guard<std::mutex> lock(mutex_);
if (initialized_) {
return;
}
minLogLevel_ = minLogLevel;
consoleOutput_ = consoleOutput;
initialized_ = true;
}
// 设置最低日志级别
void setMinLogLevel(LogLevel level) {
std::lock_guard<std::mutex> lock(mutex_);
minLogLevel_ = level;
}
// 日志输出方法
void log(LogLevel level, const std::string& message) {
if (level < minLogLevel_ || !consoleOutput_) {
return;
}
auto now = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(now);
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()) % 1000;
std::tm tm;
localtime_r(&in_time_t, &tm);
std::stringstream ss;
ss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
<< "." << std::setfill('0') << std::setw(3) << ms.count()
<< " [" << logLevelToString(level) << "] "
<< message;
std::lock_guard<std::mutex> lock(mutex_);
std::cout << ss.str() << std::endl;
}
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
private:
Logger() = default;
~Logger() = default;
std::string logLevelToString(LogLevel level) {
switch (level) {
case LogLevel::DEBUG: return "DEBUG";
case LogLevel::INFO: return "INFO";
case LogLevel::WARNING: return "WARNING";
case LogLevel::ERROR: return "ERROR";
case LogLevel::CRITICAL: return "CRITICAL";
default: return "UNKNOWN";
}
}
std::mutex mutex_;
LogLevel minLogLevel_ = LogLevel::INFO;
bool consoleOutput_ = true;
bool initialized_ = false;
};
}
#define LOG_DEBUG(message) qing::Logger::getInstance().log(LogLevel::DEBUG, message)
#define LOG_INFO(message) qing::Logger::getInstance().log(LogLevel::INFO, message)
#define LOG_WARNING(message) qing::Logger::getInstance().log(LogLevel::WARNING, message)
#define LOG_ERROR(message) qing::Logger::getInstance().log(LogLevel::ERROR, message)
#define LOG_CRITICAL(message) qing::Logger::getInstance().log(LogLevel::CRITICAL, message)
+110
View File
@@ -0,0 +1,110 @@
#pragma once
#include <us/Thread.hpp>
#include <us/ITask.hpp>
#include <us/HttpServer.hpp>
namespace qing {
namespace http = boost::beast::http;
/* ----------------
* HttpTask类 - 超文本服务器任务 */
class HttpTask: public ITask {
public:
/* 接受一个回调函数,其接受pmc::net::HttpServer对象的引用,在回调函数中对服务器进行配置 */
HttpTask(int port, std::function<void(pmc::net::HttpServer& server)> handler);
/* 在一个线程中判断线程是否正在有效运行 */
bool isRunning() override;
/* 启动该项任务 */
void start() override;
/* 停止该项任务 */
void stop() override;
private:
int port;
std::function<void(pmc::net::HttpServer& server)> handler;
std::unique_ptr<Thread> th; /* ---- 可控线程指针 */
std::unique_ptr<pmc::net::HttpServer> server; /* ---- HTTP服务器的指针 ---- */
/* 初始化线程,定义线程的行为(Http服务器) */
void init_thread();
};
/*-----------------------------------------------------------------------------*/
/* ================
* 进程托管http服务器
* ================
* 对操作进程列表的http服务器进行配置,即是输入回调函数 */
namespace process_http_server {
/* ---- 注册POST路由 ---- */
void registerRoutes(pmc::net::HttpServer& server);
/**
* @brief 解析请求体中的JSON数据
* @param body 请求体字符串
* @return JSON解析后的属性树
*/
boost::property_tree::ptree parseJsonBody(const std::string& body);
/**
* @brief 构建JSON响应
* @param success 是否成功
* @param message 消息
* @param data 附加数据
* @return JSON字符串
*/
std::string buildJsonResponse(bool success, const std::string& message,
const boost::property_tree::ptree& data = boost::property_tree::ptree());
/**
* @brief 从请求中提取target参数
* @param params 查询参数
* @return target值(空字符串表示本机)
*/
std::string getTarget(const std::unordered_map<std::string, std::string>& params);
/**
* @brief 从请求中提取exec参数
* @param params 查询参数
* @return 要执行的指令
*/
std::string getExecCommand(const std::unordered_map<std::string, std::string>& params);
/**
* @brief 从请求中提取kill参数
* @param params 查询参数
* @return 目标进程号
*/
int getPid(const std::unordered_map<std::string, std::string>& params);
/* POST方法处理器 */
http::response<http::string_body> handleList(
const http::request<http::string_body>& req,
const std::unordered_map<std::string, std::string>& params);
http::response<http::string_body> handleExec(
const http::request<http::string_body>& req,
const std::unordered_map<std::string, std::string>& params);
http::response<http::string_body> handleKill(
const http::request<http::string_body>& req,
const std::unordered_map<std::string, std::string>& params);
/** 内部实现函数 */
std::string listProcesses(const std::string& target);
std::string execCommand(const std::string& command, const std::string& target);
bool killProcess(int pid, const std::string& target);
}
}
+53
View File
@@ -0,0 +1,53 @@
#pragma once
#include <iostream>
#include <memory>
#include <list>
#include "main/ProcessTask.hh"
namespace qing {
/* -----------------
* subprocess pool 子进程池
* ----------------
* FIXME: 将列表(序列化)功能放到这里来 */
class PPool {
public:
/* CREATE PROCESS - 创建进程
*
* cmd: 启动命令 */
void crtp(const std::string& cmd);
/* CLEAR 清理 - 删除所有已经停下的进程 */
void clr();
/* 获取进程池的大小 */
size_t size() { return pool.size(); }
/* 删除一个进程,需要输入进程的下标。
*
* FIXME: 输入进程下标似乎不太自然 */
void kill(int idx);
/* 取下标运算符重载 - 取元素对象 */
ProcessTask& operator[](const size_t idx);
/* TODO: 实现迭代器和begin()、end()
* ...... */
private:
/* 进程任务的shared指针的容器 */
std::list<std::shared_ptr<ProcessTask>> pool{};
};
}
+70
View File
@@ -0,0 +1,70 @@
#pragma once
#include <boost/process.hpp>
#include <us/ITask.hpp>
namespace qing {
/* ----------------
* 【子进程任务】
* ----------------
* 输入要执行的命令,构造子进程任务
* TODO: 我们可以重定向子进程的输入和输出,实时交互 */
class ProcessTask: public ITask {
public:
/* 输入一个字符串(要执行的命令)(但是并没有执行起来) */
ProcessTask(std::string cmd): cmd(cmd) {}
/* 任务是否在运行中 */
bool isRunning() override { return p && p->running(); }
/* 启动任务 */
void start() override {
if (!isRunning())
this->p = std::make_unique<boost::process::child>(cmd); }
/* 终止该任务(并且重置子进程指针) */
void stop() override {
if (isRunning()) p->terminate();
p.reset();
}
/* 获取该任务(子进程)的命令 */
std::string check() { return this->cmd; }
/* 获取该子进程的pid(进程编号) */
pid_t pid() { return p->id(); }
private:
std::unique_ptr<boost::process::child> p; /* 子进程指针 */
std::string cmd; /* 该进程执行的命令 */
};
}
#ifdef __NEW_VER
/* ---- [子进程任务]boost.process库升级到了v2 ---- */
class ProcessTask: public ITask {
public:
ProcessTask(std::string cmd): cmd(cmd) {}
bool isRunning() override;
int getExitCode();
void start() override;
/* ---- NOTE(202606025-qing): 杀死进程失败只是打印错误信息 ---- */
void stop() override;
std::string check() {
return this->cmd;
}
pid_t pid() {
return p->id();
}
private:
boost::asio::io_context ctx; /* 异步上下文 */
std::unique_ptr<boost::process::v2::process> p; /* 子进程指针 */
boost::system::error_code exit_code; /* 进程退出的代码 */
std::string cmd; /* 要执行的命令 */
};
}
#endif
+58
View File
@@ -0,0 +1,58 @@
#pragma onces
#include "tt/Mq.h"
namespace qing {
/*
* TRANSMIT TASK 通信任务
* (创建一个通信伺服器,它收到消息就执行回调)
* (长时间伺服运行会不会有问题)
*/
class Tttask: public ITask {
public:
/* 构造【通信任务】
* msglen: 单条消息的长度
* msgcnt: 消息伺服长度
* callback: 回调函数 */
Tttask(const size_t msglen, size_t msgcnt, const sf_t callback);
/* 启动该通信伺服任务 */
void start() override;
/* 终止这个通信伺服任务
*
* TODO: 研究一下要不要释放一些资源
* TODO: 增加超时 */
void stop() override {
if (this->isRunning())
th->WaitClose();
}
/* 该任务是否在运行
*
* FIXME: 对START状态的处理还应该考虑
* FIXME: 如果在STOP状态而没有stop()任务,可能会造成线程未关闭,一直占用资源? */
bool isRunning() override;
private:
std::unique_ptr<Thread> th; /* 可控线程指针 */
std::unique_ptr<sf_t> callback; /* 回调行为(接收之后)指针 */
std::unique_ptr<Mq> mq; /* 消息队列指针 */
size_t msglen=0, msgcnt=0; /* 消息的缓存规格 */
std::string name; /* 消息队列名(进程号) */
/* 初始化通信伺服线程,
* 初始化方法就是通过传入一些函数,
* 构建线程 */
void init_thread();
};
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <iostream>
namespace qing {
/* ----------------
* 进程托管服务方法集
* ----------------
* 直接对进程组列表进行操作
*
*/
namespace pmc_mtd
{
auto list() -> std::string; /* 列出所有的进程 */
auto kill(const int pid) -> bool; /* 杀死一个进程,需提供PID */
auto exec(const std::string& cmd) -> bool; /* 执行一个进程,输入要执行的命令行 */
auto parse_self_init_list(std::string &path) -> void; /* 解析自启动脚本 */
}
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
namespace qing {
/* ----------------
* 子系统调用
* ----------------
* 通过进程间通信与子系统进行通讯,调用不同的功能
*
*/
namespace subsys_call
{
std::string send_list_and_recv_pipe(const std::string& name_mq);
std::string send_start_and_recv_pipe(const std::string& name_mq, const std::string& exec);
std::string send_kill_and_recv_pipe(const std::string& name_mq, const int kill);
}
}
+93
View File
@@ -0,0 +1,93 @@
/*
* 目前是Message Queue 的发送端(不涉及创建消息队列)
*
* FIXME: 集成发送、接收和创建
*/
#pragma once
#include <iostream>
#include <cstring>
#include <memory>
#include <boost/interprocess/ipc/message_queue.hpp>
namespace qing {
namespace bip = boost::interprocess;
using sf_t = std::function<void(const char*)>; /* 通信成功的回调函数 success */
using ef_t = std::function<void(void)>; /* 通信失败的回调函数 error */
class Mq {
public:
enum {CREATOR=0, USER=1};
Mq(const std::string& name, int msglen, size_t msgcnt, int mode = USER) {
this->name = std::string("/") + name;
this->msglen = msglen;
this->msgcnt = msgcnt;
this->mode = mode;
switch (mode) {
case USER:
mqp = std::make_unique<bip::message_queue>(bip::open_only, this->name.c_str());
break;
case CREATOR: /* 由创建者创建消息队列 */
bip::message_queue::remove(this->name.c_str());
mqp = std::make_unique<bip::message_queue>(
bip::create_only, this->name.c_str(),
msgcnt, msglen * sizeof(char)
);
break;
}
}
/* 创建者负责清理 */
~Mq() {
if (mode == CREATOR)
bip::message_queue::remove(name.c_str());
}
/* */
Mq(const Mq&) = delete;
Mq& operator=(const Mq&) = delete;
/* 发送消息 */
void send(std::string &msg)
{
if (msg.size() + 1 > msglen) /* over the len */
throw std::length_error("Message queue Send Length over");
mqp->send(msg.c_str(), msg.size() + 1, 0); /* include \0 */
}
/* 尝试接收消息 */
void recv(sf_t success, ef_t notyet) {
auto data = std::make_unique<char[]>(msglen); /* 接收缓冲区 */
unsigned int priority; /* 优先级 */
bip::message_queue::size_type recvd_size;
try { /* try_receive()返回bool类型 */
auto r = mqp->try_receive(
data.get(), msglen*sizeof(char),
recvd_size, priority
);
if (r) /* 成功接收到数据 */
success(data.get());
else /* 没有收到数据 */
notyet();
}
catch (std::exception &exp) {
std::cerr << "exception type: " << typeid(exp).name() << std::endl;
std::cerr << "exception message: " << exp.what() << std::endl;
}
}
private:
/* */
std::unique_ptr<bip::message_queue> mqp;
std::string name;
size_t msglen=0, msgcnt=0;
int mode;
};
}
+157
View File
@@ -0,0 +1,157 @@
#pragma once
#include <string>
#include <iostream>
#include <unistd.h>
#include <fcntl.h> /* open() */
#include <sys/stat.h> /* mkfifo() */
#include <sys/select.h>
namespace qing {
/* 20260309(qing): 该类不会抛出异常 */
class Pipe{
public:
static const int CREATOR = 1;
static const int USER =2;
static const ssize_t PIPE_MAX_LEN = 2048;
Pipe(const std::string& path, int mode)
: fd(-1), isCreator(mode == CREATOR) {
std::string real_path = "/tmp/pst-";
real_path += path;
fifo_path = real_path;
if (isCreator && mkfifo(fifo_path.c_str(), 0666) == -1 && errno != EEXIST) /* wr_wr_wr */
perror("mkfifo"); /* 文件已存在是正常情况,其他错误才需要处理 */
}
~Pipe() {
/* 如果打开了文件,则关闭文件 */
if (fd != -1) close(fd);
/**********************/
/* 如果管道由该对象创建,就要负责清理 */
if (isCreator) unlink(fifo_path.c_str()); /* 创建者负责清理 */
}
Pipe(const Pipe&) = delete;
Pipe& operator=(const Pipe&) = delete;
/* 这里才是打开文件的指令 - 以读模式打开,可以非阻塞 */
bool openForRead(bool nonblock = false) {
/* 设置是否以非阻塞方式打开文件 */
int flags = O_RDONLY;
if (nonblock) {
flags |= O_NONBLOCK;
}
fd = open(fifo_path.c_str(), flags);
if (fd == -1) {
perror("open for read");
return false;
}
else {
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
if (fd > max_fd) max_fd = fd;
return true;
}
}
/* 以写模式打开文件 */
bool openForWrite(/*bool nonblock = falsei*/) {
/* 写入管道是不需要阻塞/非阻塞的? */
int flags = O_WRONLY;
//if (nonblock) {
// flags |= O_NONBLOCK;
//}
fd = open(fifo_path.c_str(), flags);
if (fd == -1) {
perror("open for write");
return false;
}
else {
FD_ZERO(&write_fds);
FD_SET(fd, &write_fds);
if (fd > max_fd) max_fd = fd;
return true;
}
}
/* 写入管道,如果失败返回-1。成功返回写入的字符数。 */
ssize_t writePipe(const std::string &data) {
if (fd == -1) {
std::cerr << "Pipe not opened for writing" << std::endl;
return -1;
}
else {
return write(fd, data.c_str(), data.size());
}
}
/* 将探测与读取解耦,使用者可以自行决定要不要阻塞 */
bool waitForRead(int timeout_sec = 0, int timeout_usec = 0) {
/* 如果文件没打开,等待是失败的 */
if (fd == -1) return false;
fd_set temp_fds = read_fds;
struct timeval timeout = {timeout_sec, timeout_usec};
int ret = select(max_fd + 1, &temp_fds, nullptr, nullptr, &timeout);
if (ret == -1) {
perror("select");
return false;
}
else {
return ret > 0 && FD_ISSET(fd, &temp_fds);
}
}
/* 读取数据到字符串,返回实际读取的字节数 */
ssize_t readPipe(std::string *output) {
if (fd == -1) {
std::cerr << "Pipe not opened for reading" << std::endl;
return -1;
}
else
{
char buffer[PIPE_MAX_LEN];
ssize_t n = read(fd, buffer, sizeof(buffer) - 1);
if (n >0) {
buffer[n] = '\0';
*output = buffer;
}
else if (n == 0) {
/* 管道写入端关闭 */
*output = "";
}
else {
perror("read");
}
return n;
}
}
private:
std::string fifo_path;
int fd;
bool isCreator;
fd_set read_fds;
fd_set write_fds;
fd_set except_fds;
int max_fd;
};
}