RedisServer解析(一)

文章目录


前言

之前解析了server对buttonrpc的使用,现在分析server是如何接受client发送到信息完成对应的redis操作

RedisServer

getInstance

cpp 复制代码
RedisServer* RedisServer::getInstance()
{
	static RedisServer redis;
	return &redis;
}

单例模式中的懒汉模式。因为本项目是单线程项目,不存在多个线程同时调用getinstance的情况,因此不需要额外处理。这里提供在多线程中实现单例模式懒汉模式的方法。

cpp 复制代码
#include <mutex>
class RedisServer {
public:
    static RedisServer* getInstance();
private:
    RedisServer();
    static std::once_flag initFlag; // 用于控制初始化的全局变量
};
std::once_flag RedisServer::initFlag;
RedisServer* RedisServer::getInstance() {
    static RedisServer* instance = nullptr;
    std::call_once(initFlag, []() {
        instance = new RedisServer();
    });
    return instance;
}

start

cpp 复制代码
void RedisServer::start() {
    signal(SIGINT, signalHandler);  
    printLogo();
    printStartMessage();
}

注册sigint信号处理函数,sighandler的作用是在使用sigint时将缓冲区刷新一遍。

client

接下来查看server绑定的函数server.bind("redis_command", &RedisServer::handleClient, RedisServer::getInstance());

getinstance是实例,redis_command是map的key值。handleClient则是命令处理函数,client通过此函数 string res = client.call<string>("redis_command", message).val();向server请求。

因此我们接下来查看client的请求过程。

client.call

cpp 复制代码
inline buttonrpc::value_t<R> buttonrpc::call(std::string name, P1 p1)
{
	Serializer ds;
	ds << name << p1;
	return net_call<R>(ds);
}

Serializer对<<进行了重载,在这里就是将name和参数1对内容写入ds.m_iodevice。然后调用net_call。

net_call

cpp 复制代码
template<typename R>
inline buttonrpc::value_t<R> buttonrpc::net_call(Serializer& ds)
{
	zmq::message_t request(ds.size() + 1);
	memcpy(request.data(), ds.data(), ds.size());
	if (m_error_code != RPC_ERR_RECV_TIMEOUT) {
		send(request);
	}
	zmq::message_t reply;
	recv(reply);
	value_t<R> val;
	if (reply.size() == 0) {
		// timeout
		m_error_code = RPC_ERR_RECV_TIMEOUT;
		val.set_code(RPC_ERR_RECV_TIMEOUT);
		val.set_msg("recv timeout");
		return val;
	}
	m_error_code = RPC_ERR_SUCCESS;
	ds.clear();
	ds.write_raw_data((char*)reply.data(), reply.size());
	ds.reset();
	ds >> val;
	return val;
}

代码比较简答,send(request)将信息发送给服务端,服务端对信息进行处理,其处理逻辑在上一遍博客中已经讲过了。在send和recv之后就是一次信息的处理。在call_函数中有代码段

cpp 复制代码
 auto fun = m_handlers[name]; //获取函数
 fun(ds, data, len); 

我们知道这其实就是调用了一次handleClient函数。

handleClient

cpp 复制代码
if (!startMulti) {
   std::shared_ptr<CommandParser> commandParser = flyweightFactory->getParser(command);
    if (commandParser == nullptr) {
        responseMessage = "Error: Command '" + command + "' not recognized.";
    }
    else {
        try {
            responseMessage = commandParser->parse(tokens);
        }
        catch (const std::exception& e) {
            responseMessage = "Error processing command '" + command + "': " + e.what();
        }
    }

    // 发送响应消息回客户端
    return responseMessage;
}

代码逻辑比较清晰,就是根据输入的command进行不同的操作。一些特殊的命令进行单独处理,而对于常规的命令则采用统一的入口flyweightFactory->getParser(command)。并对返回的信息执行responseMessage = commandParser->parse(tokens);

参考

zeromq

相关推荐
汉克老师2 分钟前
CSP-J 初赛(以满分为目标):第二十七课 《图的遍历——BFS广度优先搜索——像“水波纹”一样,一层一层地搜索》
c++·csp-j·小学生·学c++编程
闻缺陷则喜何志丹5 分钟前
【动态规划】P3609 [USACO17JAN] Hoof, Paper, Scissor G
c++·算法·动态规划·洛谷
tedcloud1238 分钟前
OpenLogi 怎么搭建?用 Rust 打造一个轻量的 Logitech 外设管理工具
linux·运维·服务器·开发语言·后端·rust·开源
与自己和解74111 分钟前
使用ssh实现 VScode 直连 ubuntu
vscode·ubuntu·ssh
AAA代码批发商14 分钟前
Days 39 Linux C 开发之 SQLite 数据库完整学习笔记
linux·c语言·数据库
汉克老师23 分钟前
CSP-J 初赛(以满分为目标):第二十六课 《图的遍历——DFS深度优先搜索——从“树的先序遍历”走进真正的图世界》
c++·csp-j·小学生·学c++编程
程序猿编码29 分钟前
基于GGML的C++17轻量化语音推理引擎:说话人识别与语音分析技术全解析
开发语言·c++·pytorch·深度学习·神经网络·大模型
额额额对了1 小时前
Linux 数据库开发实战:使用 C 语言与 SQLite3 构建轻量级终端词典
linux·数据库·oracle
爱笑鱼1 小时前
Android 系统启动机制(六):Zygote 创建 App 为什么走 Socket?哪些是源码事实,哪些是架构解释?
android·linux
影视飓风TIM1 小时前
C++哈希表深度剖析:冲突处理、rehash、迭代器与unordered容器封装
c++·哈希算法·散列表