十一、实现逻辑层

系列文章目录:C++ asio网络编程-CSDN博客

1、服务器架构设计

2、单例模板类

我们的LogicSystem类为单例类,可以只把这个类写为单例,也可以写一个单例模板类,让其它类继承它就可以形成单例。这里选择第二种,因为后面可能还会实现其他的单例类。

cpp 复制代码
#pragma once
#include <memory>
#include <mutex>
#include <iostream>

template <typename T>
class Singleton
{
public:
	~Singleton() {
		std::cout << "singleton destruct" << std::endl;
	}

	static std::shared_ptr<T> getInstance() {
		static std::once_flag s_flag;
		std::call_once(s_flag, [&]() {
			_instance = std::shared_ptr<T>(new T);
		});
		return _instance;
	}

	void printAddress() {
		std::cout << _instance->get() << std::endl;
	}


protected:
	Singleton() = default;
	Singleton(const Singleton<T>&) = delete;
	Singleton& operator = (const Singleton<T>& st) = delete;

	static std::shared_ptr<T> _instance;
};

template <typename T>
std::shared_ptr<T> Singleton<T>::_instance = nullptr;

C++基础好的同学应该很容易看明白,有不明白的地方可以利用一些ai工具解读一下,也很简单。

3、LogicSystem类

cpp 复制代码
#pragma once
#include "Singleton.h"
#include <queue>
#include <thread>
#include "const.h"
#include "Session.h"
#include <map>
#include <functional>
#include <json/json.h>
#include <json/value.h>
#include <json/reader.h>

class LogicNode;
class Session;

typedef std::function<void(std::shared_ptr<Session>, const short& msg_id, const std::string& msg_data)> FunCallBack;

class LogicSystem : public Singleton<LogicSystem>
{
	friend class Singleton<LogicSystem>;

public:
	~LogicSystem();

	void postMsgToQue(std::shared_ptr<LogicNode> msg);

private:
	LogicSystem();
	void registerCallBacks();
	void helloWordCallBack(std::shared_ptr<Session>, const short& msg_id, const std::string& msg_data);
	void dealMsg();

	std::queue<std::shared_ptr<LogicNode>> _msg_que;  // 逻辑队列
	std::mutex _mutex;
	std::condition_variable _consume; // 条件变量,控制当逻辑队列为空时保证线程暂时挂起等待,不要干扰其他线程
	std::thread _worker_thread;
	bool _b_stop;  // 停止信号,控制逻辑类中止工作线程
	std::map<short, FunCallBack> _fun_callback; // 回调函数的map,根据id查找对应的逻辑处理函数
};
cpp 复制代码
#include "LogicSystem.h"

LogicSystem::~LogicSystem()
{
	_b_stop = true;
	_consume.notify_one();
	_worker_thread.join();
}

void LogicSystem::postMsgToQue(std::shared_ptr<LogicNode> msg)
{
	std::unique_lock<std::mutex> ulock(_mutex);
	_msg_que.push(msg);

	if (_msg_que.size() == 1) {
		_consume.notify_one();
	}
}

LogicSystem::LogicSystem() : _b_stop(false)
{
	registerCallBacks();
	_worker_thread = std::thread(&LogicSystem::dealMsg, this);
}

void LogicSystem::registerCallBacks()
{
	_fun_callback[MSG_HELLO_WORD] = std::bind(&LogicSystem::helloWordCallBack, this,
		std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
}

void LogicSystem::helloWordCallBack(std::shared_ptr<Session> session, const short& msg_id, const std::string& msg_data)
{
	Json::Reader reader;
	Json::Value root;
	reader.parse(msg_data, root);
	std::cout << "receive msg id is " << root["id"].asInt() << "msg data is " 
		<< root["data"].asString() << std::endl;
	root["data"] = "server has receive msg: " + root["data"].asString();

	std::string return_str = root.toStyledString();
	session->send(return_str, root["id"].asInt());
}

void LogicSystem::dealMsg()
{
	for (;;) {
		std::unique_lock<std::mutex> ulock(_mutex);
		// 队列为空并且正在处理消息则用条件变量等待
		while (_msg_que.empty() && !_b_stop) {
			_consume.wait(ulock);  // 先释放资源再解锁
		}
		// 关闭状态时,取出逻辑队列所有数据及时处理,并且退出循环
		if (_b_stop) {
			while (!_msg_que.empty()) {
				auto msg_node = _msg_que.front();
				std::cout << "receive msg id: " << msg_node->_recvNode->_msg_id << std::endl;
				auto call_back_iter = _fun_callback.find(msg_node->_recvNode->_msg_id);
				if (call_back_iter == _fun_callback.end()) {
					_msg_que.pop();
					continue;
				}
				call_back_iter->second(msg_node->_session, 
					msg_node->_recvNode->_msg_id, 
					std::string(msg_node->_recvNode->_data, msg_node->_recvNode->_cur_len));
				_msg_que.pop();
			}
			break;
		}
		// 没有停服,并且队列有数据
		auto msg_node = _msg_que.front();
		std::cout << "receive msg id: " << msg_node->_recvNode->_msg_id << std::endl;
		auto call_back_iter = _fun_callback.find(msg_node->_recvNode->_msg_id);
		if (call_back_iter == _fun_callback.end()) {
			_msg_que.pop();
			continue;
		}
		call_back_iter->second(msg_node->_session,
			msg_node->_recvNode->_msg_id,
			std::string(msg_node->_recvNode->_data, msg_node->_recvNode->_cur_len));
		_msg_que.pop();
	}
}

MSG_HELLO_WORD定义在const.h中,表示消息id

cpp 复制代码
enum MSG_IDS {
	MSG_HELLO_WORD = 1001
};

4、逻辑节点

在Session.h中,我们可以添加一个逻辑节点类

cpp 复制代码
class LogicNode
{
	friend class LogicSystem;
public:
    // 第二个参数是为了防止session被提前释放
	LogicNode(std::shared_ptr<Session>, std::shared_ptr<RecvNode>); 
private:
	std::shared_ptr<Session> _session;
	std::shared_ptr<RecvNode> _recvNode;
};
cpp 复制代码
LogicNode::LogicNode(std::shared_ptr<Session> session, std::shared_ptr<RecvNode> recvNode)
	: _session(session), _recvNode(recvNode)
{
}
相关推荐
j_xxx404_3 小时前
Linux:静态链接与动态链接深度解析
linux·运维·服务器·c++·人工智能
Johnstons3 小时前
Wireshark ExpertInfo是什么?一文讲透异常分级、适用场景、和传统抓包阅读的区别与排查标准
网络·测试工具·wireshark·es
alxraves3 小时前
医疗器械软件注册指导原则注意事项
网络·安全·健康医疗·制造
c++之路4 小时前
C++23概述
java·c++·c++23
墨风如雪4 小时前
别被“高价建站”劝退了!我跑了多年的 WordPress 架构,一年只花 $25.7
服务器
云飞云共享云桌面4 小时前
东莞智能装备工厂数字化实践—研发部门10名SolidWorks设计共享一台云主机流畅设计
服务器·自动化·汽车·负载均衡·制造
专注API从业者5 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
xingyuzhisuan5 小时前
稳定性考验:连续跑7天,哪家云主机不重启、不掉线?
服务器·人工智能·gpu算力
jsons15 小时前
给每台虚拟机设置独立控制台密码
linux·运维·服务器
学涯乐码堂主5 小时前
有趣的“打擂台算法”
c++·算法·青少年编程·gesp