Files
micro_servers/lci/extra/dashun/dashun/Main.cpp
T
2026-08-02 20:15:07 +08:00

540 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#define _CRT_SECURE_NO_WARNINGS
#include "Th.hpp"
#include "Pls.hpp"
#include "args.hxx"
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <uv.h>
#ifdef _WIN32
#include <Windows.h>
#undef UNICODE
#undef _UNICODE
#endif
#include <iostream>
#include <memory>
#include <atomic>
using namespace boost::interprocess;
// 定义分配器类型
using CharAllocator = boost::interprocess::allocator<
char,
boost::interprocess::managed_shared_memory::segment_manager
>;
// 定义共享内存字符串类型
using SharedString = boost::interprocess::basic_string<
char,
std::char_traits<char>,
CharAllocator
>;
namespace qing {
// 监听线程
class LTh : public qing::Th {
public:
LTh(const std::string& name) {
this->name = name;
nameMem = name + "_MEM";
nameMtx = name + "_MTX";
namePtr = name + "_PTR";
nameRet = name + "_RET";
this->WakeEvent = [this] {
try {
// 先移除可能存在的旧共享内存
this->del_shared();
// 创建共享对象
this->create_shared();
// 线程进入运行态
this->run();
}
catch (interprocess_exception& ex) {
// 输出错误信息
std::cerr << ex.what() << std::endl;
// 线程静止
this->stop();
}
};
this->LoopEvent = [this] {
this->recv_shared_and_action();
// 等待
//
// 优化方案:使用信号,有新消息进来给沉默进程发送信号
// 而不是休眠定长时间检查
std::this_thread::sleep_for(std::chrono::milliseconds(10));
};
this->ClearEvent = [this] {
// 移除共享对象
this->del_shared();
};
}
[[noreturn]] static auto send_shared_msg(const std::string& to, const std::string& msg) -> void {
std::string nameMem = to + "_MEM";
std::string nameMtx = to + "_MTX";
std::string namePtr = to + "_PTR";
std::string nameRet = to + "_RET";
try {
// 打开共享内存
managed_shared_memory segment(open_only, nameMem.c_str());
// 构造一个命名互斥量
named_mutex mutex(open_or_create, nameMtx.c_str());
// 在共享内存中创建一个字符串
SharedString* str = segment.construct<SharedString>(namePtr.c_str())(
msg.c_str(), // 初始值(空字符串)
segment.get_allocator<char>() // 必须传入分配器
);
// 不延时的话可能会抢占,也许应该想一个两全其美的方法
std::this_thread::sleep_for(std::chrono::milliseconds(100));
{
// 加锁
std::lock_guard<named_mutex> lk(mutex);
// 获取消息
std::pair<SharedString*, std::size_t> msg = segment.find<SharedString>(nameRet.c_str());
if (msg.first) {
// 输出
std::cout << std::endl << *msg.first << std::endl;
// 销毁
segment.destroy<SharedString>(nameRet.c_str());
}
}
}
catch (interprocess_exception& ex) {
std::cerr << "Writer Error: " << ex.what() << std::endl;
}
}
private:
std::string name;
std::string nameMem;
std::string nameMtx;
std::string namePtr;
std::string nameRet;
std::unique_ptr<managed_shared_memory> segment;
std::unique_ptr<named_mutex> mutex;
std::pair<SharedString*, std::size_t> msg;
qing::Pls pls;
inline void create_shared() {
//////////////////////////////
// 删除可能存在的共享变量
this->del_shared();
//////////////////////////////
// 创建共享内存
segment = std::make_unique<managed_shared_memory>(create_only, (nameMem).c_str(), 65536);
// 创建互斥量
mutex = std::make_unique<named_mutex>(create_only, (nameMtx).c_str());
}
inline auto del_shared() -> void {
// 先移除可能存在的旧共享内存
shared_memory_object::remove(nameMem.c_str());
// 移除可能存在的互斥量
named_mutex::remove(nameMtx.c_str());
}
inline auto recv_shared_and_action() -> void
try {
// 加锁
std::lock_guard<named_mutex> lock(*mutex);
// 查找共享字符串
msg = segment->find<SharedString>(namePtr.c_str());
if (msg.first) { // 找到
std::cout << "Reader read: " << *msg.first << std::endl;
std::string ret = this->lexer(std::string((msg.first)->data(), (msg.first)->size()));
// 在共享内存中创建一个字符串
SharedString* str = segment->construct<SharedString>(nameRet.c_str())(
ret.c_str(), // 初始值(空字符串)
segment->get_allocator<char>() // 必须传入分配器
);
// 销毁writer创建的变量
segment->destroy<SharedString>(namePtr.c_str());
}
}
catch (interprocess_exception& ex) {
std::cerr << ex.what() << std::endl;
}
// 简易词法分析器
std::string lexer(std::string tmp) {
// 要返回的消息
std::string ret = "OK";
if (tmp == "list") {
ret = pls.initialize();
}
else if (tmp.starts_with("kill ")) {
pls.kill(std::stoi(tmp.substr(5)));
}
else if (tmp == "clear") {
pls.clear();
}
//else if (tmp == "shut") {
// this->shut();
//} //关闭不了程序
else {
// 这个分支最好返回自己是否出现了异常
pls.exec(tmp.c_str(), {});
}
// 返回消息
return ret;
}
};
}
// 线程指针
std::unique_ptr<qing::Th> th;
// 全局标志,指示是否应该退出
std::atomic<bool> should_exit(false);
// 子系统的名称(全局参数)
std::string name;
// 消息
std::string msg;
// Windows异步句柄,用于信号转发
#ifdef _WIN32
uv_async_t async_handle;
SERVICE_STATUS_HANDLE hStatus;
SERVICE_STATUS status;
#endif
////////////////////////
////////////////////////
// 解析命令行参数
//
//
// 创建参数解析器
args::ArgumentParser parser("这是一个脚本托管服务。", "请使用专门的通信程序(或本程序自己)进行操作。");
// 显示帮助信息的标志
args::HelpFlag help(parser, "帮助", "显示帮助信息", { 'h', "help" });
// 启用守护进程
args::Flag daemon(parser, "守护进程", "启动守护进程", { 'd', "daemon" });
// 子系统路径
args::ValueFlag<std::string> subSys(parser, "子系统", "输入子系统文件夹的路径", { 's', "sys" });
// 要发送的子系统名字
args::ValueFlag<std::string> arg_to(parser, "发送目标", "输入要发送的子系统路径", { 't', "to" });
// 要发送的信息
args::ValueFlag<std::string> arg_msg(parser, "消息", "输入要发送的消息(<path>|list|kill <pid>| clear)", { 'm', "msg" });
[[noreturn]] static auto parse_args(int argc, char** argv) -> void {
// 解析命令行参数
try {
parser.ParseCLI(argc, argv);
}
catch (const args::Help&) {
std::cout << parser;
exit(0);
}
catch (const args::ParseError& e) {
std::cerr << e.what() << std::endl;
std::cerr << parser;
exit(1);
}
catch (const args::ValidationError& e) {
std::cerr << e.what() << std::endl;
std::cerr << parser;
exit(1);
}
}
////////////////////////
////////////////////////
// 信号处理回调函数
[[noreturn]] static void on_signal(uv_signal_t* handle, int signum) {
std::cout << "\n收到退出信号 " << signum << std::endl;
// 防止重复处理退出信号
if (should_exit) return;
should_exit = true;
// 停止信号监听
uv_signal_stop(handle);
// 执行清理
if (th)
th->WaitClose();
// 关闭事件循环
uv_stop(uv_default_loop());
}
// Windows异步回调函数
#ifdef _WIN32
[[noreturn]] static void async_callback(uv_async_t* handle) {
std::cout << 1 << std::endl;
// 这里可以触发退出流程或其他需要在事件循环中处理的操作
if (!should_exit) {
on_signal(nullptr, SIGINT); // 模拟收到SIGINT信号
}
}
// Windows控制台事件处理程序
static BOOL WINAPI console_handler(DWORD signal) {
std::cout << 1 << std::endl;
switch (signal) {
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
// 使用异步句柄将信号转发到libuv事件循环
uv_async_send(&async_handle);
return TRUE;
default:
return FALSE;
}
}
#endif
////////////////////////////////////
////////////////////////////////////
// 分支
//
//
// 发送消息分支
static inline auto SendMsgBranch() -> void {
qing::LTh::send_shared_msg(name, msg);
}
// 守护进程分支
static inline auto DaemonBranch() -> void {
th = std::make_unique<qing::LTh>(name);
th->Activate();
th->WaitStart();
//th->Wait();
}
//
// 分支选择器
[[noreturn]] static auto BranchSelector(uv_idle_t* handle) {
if (should_exit) {
uv_idle_stop(handle);
return;
}
if (th) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
return;
}
if (arg_to && arg_msg) { // 发送消息分支
name = args::get(arg_to);
msg = args::get(arg_msg);
SendMsgBranch();
// 退出
should_exit = true;
// 关闭事件循环
uv_stop(uv_default_loop());
}
else if ((daemon && arg_to) || 1) { // 守护进程分支
std::cout << "程序启动,开始运行..." << std::endl;
std::cout << "按下 CTRL+C 退出程序" << std::endl;
name = (arg_to) ? args::get(arg_to) : "test";
DaemonBranch();
}
else {
//输出帮助文本
std::cout << parser;
// 退出
should_exit = true;
// 关闭事件循环
uv_stop(uv_default_loop());
}
}
////////////////////////////////////
int MyMain(int argc, char** argv) {
parse_args(argc, argv);
//////////
// 信号
//
//
#ifdef _WIN32
// 初始化Windows异步句柄
uv_async_init(uv_default_loop(), &async_handle, async_callback);
// 设置控制台事件处理程序
if (!SetConsoleCtrlHandler(console_handler, TRUE)) {
std::cerr << "无法设置控制台控制处理程序" << std::endl;
return 1;
}
#else
// Unix平台:确保信号不会被忽略
signal(SIGINT, [](int signum) { /* 留给libuv处理 */ });
signal(SIGTERM, [](int signum) { /* 留给libuv处理 */ });
#endif
// 初始化信号处理器
uv_signal_t sig_int, sig_term;
// 监听SIGINT 信号(CTRL + C)
uv_signal_init(uv_default_loop(), &sig_int);
uv_signal_start(&sig_int, on_signal, SIGINT);
// 监听 SIGTERM信号
uv_signal_init(uv_default_loop(), &sig_term);
uv_signal_start(&sig_term, on_signal, SIGTERM);
#ifdef _WIN32
// WINDOWS平台特有的信号
uv_signal_t sig_break;
uv_signal_init(uv_default_loop(), &sig_break);
uv_signal_start(&sig_break, on_signal, SIGBREAK);
#endif
// 设置任务
uv_idle_t idle;
uv_idle_init(uv_default_loop(), &idle);
uv_idle_start(&idle, ::BranchSelector);
// 运行事件循环
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
// 释放资源
uv_close((uv_handle_t*)&sig_int, nullptr);
uv_close((uv_handle_t*)&sig_term, nullptr);
#ifdef _WIN32
uv_close((uv_handle_t*)&sig_break, nullptr);
uv_close((uv_handle_t*)&async_handle, nullptr);
// 移除控制台事件处理程序
SetConsoleCtrlHandler(console_handler, FALSE);
#endif
uv_close((uv_handle_t*)&idle, nullptr);
// 清理事件循环
uv_loop_close(uv_default_loop());
std::cout << "程序已经退出" << std::endl;
return 0;
}
#ifdef _WIN32
[[noreturn]] void ReportStatus(DWORD state) {
status.dwCurrentState = state;
SetServiceStatus(hStatus, &status);
}
[[noreturn]] void ServiceCtrlHandler(DWORD control) {
if (control == SERVICE_CONTROL_STOP) {
ReportStatus(SERVICE_STOP_PENDING);
// 执行清理
ReportStatus(SERVICE_STOPPED);
}
}
[[noreturn]] void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {
hStatus = RegisterServiceCtrlHandler(L"大顺脚本", ServiceCtrlHandler);
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ReportStatus(SERVICE_RUNNING); // 告诉SCM服务已启动
//服务主逻辑
MyMain(argc, argv);
}
#endif