[分布式网络通讯框架]----MprpcController以及Logger类

在calluserservice.cc中,使用UserServiceRpc_Stub类的时候,我们最终调用形式为:stub.Login(&controller,&request,&response,nullptr);
注意到其中有一个controller对象,这个是由MprpcController类定义出来的对象,那么这个类的作用是什么呢?

  • 首先我们来看 Login() 的底层实现,传入的controller到底是一个什么。
    在这里插入图片描述
  • 可以看到,controller实际上是RpcController* 类;
    *
  • RpcController* 类实际上是一个抽象类,底层封装了各类纯虚函数,我们通过继承这个类,并且重写对应的函数,来判断rpc的调用是否成功。
  • 如果不判断是否调用成功就直接读取response ,是假设request成功的,在其中不会发生任何的错误,但是这种情况是理想化的,在其中会出现很多问题。如:网络建立连接错误 各种地方的return exit等 都会造成没有response响应。

MprpcController类

class MprpcController:public google::protobuf::RpcController
{省略...........省略
};
  • 很明确 它是继承了 google::protobuf::RpcController类。

重要成员变量

bool m_failed; 
  • 记录rpc方法执行过程中的状态
std::string m_errText;
  • 记录rpc方法执行过程中的错误信息

重要成员函数

构造函数

MprpcController::MprpcController()
{m_failed = false;m_errText = "";
}
  • 初始化成员变量

void Reset();

void MprpcController::Reset()
{m_failed = false;m_errText = "";
}
  • 重置成员变量的值

bool Failed() const;

bool MprpcController::Failed() const
{return m_failed;
}
  • 返回rpc方法执行过程中的状态,如果是false,我们将不会读取response值。

std::string ErrorText() const;

std::string MprpcController::ErrorText() const
{return m_errText;
}
  • 返回rpc方法执行过程中的错误信息。

void SetFailed(const std::string& reason);

void MprpcController::SetFailed(const std::string &reason)
{m_failed = true;m_errText = reason;
}
  • 在我们调用的过程中,通过该函数,写错误原因。

例如

if(rpcHeader.SerializeToString(&rpc_header_str))
{header_size=rpc_header_str.size();
}
else
{controller->SetFailed("Serialize rpc header error!");return;
}

整个项目的主体部分,就到此结束了,剩余一个logger类,这也是我们在做大型项目的必备类,通过日志,可以简单明了的帮我们分析到程序的问题所在,这里采用了异步,同时有多个worker线程都会向日志queue队列中写日志,而只有一个线程读日志queue,向指定文件中写日志文件。

Logger类

为什么需要异步记录日志

因为基于muduo网络库进行网络通讯的,muduo通过多线程来处理并发连接,要添加日志模块那么就会有多个线程写日志信息的情况。这样的话就必须要实现一个保证线程安全的日志队列。所以需要启动一个日志线程,专门对日志队列写日志。

保证线程安全的日志队列类

为了保证线程安全,项目中提供了模板类 lockqueue template<typename T>,它用于实现异步写日志的日志队列,主要包含 push 和 pop 两个方法。

重要成员变量

std::queue<T> m_queue;
std::mutex m_mutex;
std::condition_variable m_condvariable;
  • 队列
  • 条件变量

重要成员函数

void Push(const T &data)
void Push(const T &data)
{std::lock_guard<std::mutex> lock(m_mutex);m_queue.push(data);m_condvariable.notify_one();
}
  • push 方法可以被多个 worker 线程调用以将数据添加到日志队列中
T Pop()
T Pop()
{std::unique_lock<std::mutex> lock(m_mutex);while(m_queue.empty()){//日志队列为空,线程进入wait状态,并且释放锁m_condvariable.wait(lock);}T data=m_queue.front();m_queue.pop();return data;
}
  • pop 方法则只能由一个线程读取队列并将其内容写入日志文件。

实际上,各个线程通过push 方法使用了 std::lock_guardstd::mutex进行加锁,然后将数据添加到队列中,最后通过条件变量std::condition_variable唤醒 pop 方法所在的线程。pop 方法获得锁后,然后进入一个 while 循环,在循环中检查队列是否为空,如果为空,则调用条件变量的 wait 方法使当前线程阻塞等待日志的产生。当队列不为空时,将队头元素取出,并从队列中删除。最后释放锁并返回取出的队头元素。

优点:通过这种方式实现日志队列的异步操作,可以让写日志的线程和写文件的线程分别跑在不同的线程中,避免了日志写操作对主程序的性能影响。

Logger类

日志类属于是单例模式,确保了整个应用程序中只有一个logger实例。

重要成员变量

enum LogLevel //日志级别
{INFO,//普通信息ERROR,//错误信息
};int m_loglevel;//记录日志级别LockQueue<std::string> m_lckQue;//日志缓冲队列

重要成员函数

Logger()
Logger::Logger()
{//启动专门的写日志线程std::thread writeLogTask([&](){for(;;){//获取当天的日期,然后取日志信息,写入相应的日志文件当中 a+time_t now=time(nullptr);tm *nowtm = localtime(&now);char file_name[128];sprintf(file_name,"%d-%d-%d-log.txt",nowtm->tm_year+1900,nowtm->tm_mon+1,nowtm->tm_mday);FILE *pf = fopen(file_name,"a+");if(pf==nullptr){std::cout<<"logger file: "<<file_name<<" open error!"<<std::endl;exit(EXIT_FAILURE);}std::string msg=m_lckQue.Pop();char time_buf[128]={0};sprintf(time_buf,"%d:%d:%d=> [%s] ",nowtm->tm_hour,nowtm->tm_min,nowtm->tm_sec,(m_loglevel==INFO?"INFO":"ERROR"));msg.insert(0,time_buf);msg.append("\n");fputs(msg.c_str(),pf);fclose(pf);}});//设置分离线程,守护线程writeLogTask.detach();
}
  • 在logger的构造函数中,发起了一个线程writelogtask,该线程循环执行以下操作, 该线程会一直运行,为整个应用程序提供日志服务;
  1. 调用系统localtime函数获取当前时间,尝试打开当日的日志文件
  2. 调用lockqueue类的pop()函数,从lockqueue中获取缓存的日志信息;
  3. 获取时分秒时间,以及根据日志级别,添加日志级别前缀,并将该条日志写入日志文件中
  • 设置分离线程,守护线程
static Logger& GetInstance();
Logger &Logger::GetInstance()
{static Logger logger;return logger;
}
  • 获取唯一单例对象
void SetLogLevel(LogLevel level);
void Logger::SetLogLevel(LogLevel level)
{m_loglevel=level;
}
  • 设置日志级别
void Log(std::string msg);
void Logger::Log(std::string msg)
{m_lckQue.Push(msg);
}
  • 把日志信息写入Lockqueue缓冲区当中

和muduo网络库中的实现类似,本项目也提供了日志的宏,它接受一个格式化的日志消息和可变数量的参数。并为了避免展开时出错,我们采用了do-while(0)语法在实际使用过程中,log_info(“xxx %d %s”, 20, “xxxx”) 可以被展开。

#define LOG_INFO(logmsgformat, ...)\do\{\Logger &logger =Logger::GetInstance();\logger.SetLogLevel(INFO);\char c[1024]={0};\snprintf(c,1024,logmsgformat,##__VA_ARGS__);\logger.Log(c);\}while (0);#define LOG_ERROR(logmsgformat, ...)\do\{\Logger &logger =Logger::GetInstance();\logger.SetLogLevel(ERROR);\char c[1024]={0};\snprintf(c,1024,logmsgformat,##__VA_ARGS__);\logger.Log(c);\}while (0);
  • 在宏内部,获取logger的实例
  • 设置日志级别为info;
  • 创建一个长度为1024的char数组c,使用snprintf函数将格式化字符串(logmsgformat) 和可变参数(va_args)写入这个数组中;
  • 调用logger的log函数将日志消息写入日志文件中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/37982.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单片机学习(16)--直流电机驱动

直流电机驱动 15.1直流电机驱动基础知识1.直流电机介绍2.电机驱动电路3.PWM介绍 15.2LED呼吸灯和直流电机调速1.LED呼吸灯代码2.直流电机调速&#xff08;1&#xff09;产生PWM的方法&#xff08;2&#xff09;工程目录&#xff08;3&#xff09;main.c函数 15.1直流电机驱动基…

isdecimal()方法——判断字符串是否只包含十进制字符

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 isdecimal()方法用于检查字符串是否只包含十进制字符。这种方法只适用于unicode对象。 注意&#xff1a;定义一个十进制字符串&#xff0c…

SpringCloud中复制模块然后粘贴,文件图标缺少蓝色方块

再maven中点击&#xff0b;号&#xff0c;把当前pom文件交给maven管理即可

RabbitMq的基础及springAmqp的使用

RabbitMq 官网:RabbitMQ: One broker to queue them all | RabbitMQ 什么是MQ&#xff1f; mq就是消息队列&#xff0c;消息队列遵循这先入先出原则。一般用来解决应用解耦&#xff0c;异步消息&#xff0c;流量削峰等问题&#xff0c;实现高性能&#xff0c;高可用&#xf…

容器技术-docker2

容器化技术Docker Docker介绍 官网&#xff1a; docker.io docker.com 公司名称&#xff1a;原名dotCloud 14年改名为docker 容器产品&#xff1a;docker 16年已经被更名为Moby docker-hub docker.io docker容器历史 和虚拟机一样&#xff0c;容器技术也是一种资源隔…

java基于ssm+jsp 二手手机回收平台系统

1前台首页功能模块 二手手机回收平台系统&#xff0c;在系统首页可以查看首页、手机商城、新闻资讯、我的、跳转到后台、购物车等内容&#xff0c;如图1所示。 图1前台首页功能界面图 用户注册&#xff0c;在用户注册页面可以填写账号、密码、姓名、手机、邮箱、照片、地址、…

深度解析RocketMq源码-消息推送、持久化、消费全流程

1.绪论 前面的几篇文章都剖析了broker的存储文件。那么生产者发送一条消息到达broker过后是如何处理的&#xff0c;这条消息结果什么处理过后&#xff0c;消费者才能够消费这条消息。接下来&#xff0c;带我们将仔细剖析一下一条消息从生产者生产消息&#xff0c;到到达broker…

在线字节大端序小端序转换器

具体请前往&#xff1a;在线字节大端序小端序转换器

操作系统期末复习真题四

一、前言&#x1f680;&#x1f680;&#x1f680; 小郑在刷题的过程中帮大家整理了一些常见的考试题目&#xff0c;以及易于遗忘的知识点&#xff0c;希望对大家有所帮助。 二、正文☀️☀️☀️ 1.OS的不确定性是指(ABC)。 A.程序的运行次序不确定 B.程序多次运行的时间不…

独立开发者系列(13)——示例理解面向对象与过程

专业术语晦涩难懂&#xff0c;特别是当你没有写过稍微大点的系统的时候&#xff0c;你要理解这里面的区别很难。 从最简单的早期我们学习开始&#xff0c;我们除了练习hello world掌握了入门函数之后&#xff0c;基本都再练习算法。比如水仙花数的获取&#xff0c;冒泡排序&…

Redis的使用和原理

目录 1.初识Redis 1.1 Redis是什么&#xff1f; 1.2 Redis的特性 1.2.1 速度快 1.2.2 基于键值对的数据结构服务器 1.2.3 丰富的功能 1.2.4 简单稳定 1.2.5 持久化 1.2.6 主从复制 1.2.7 高可用和分布式 1.3 Redis的使用场景 1.3.1 缓存 1.3.2 排行榜系统 1.3.3 计数器应用 1.3…

【操作系统期末速成】 EP04 | 学习笔记(基于五道口一只鸭)

文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、正文&#xff1a;☀️☀️☀️2.1 考点七&#xff1a;进程通信2.2 考点八&#xff1a;线程的概念2.3 考点九&#xff1a;处理机调度的概念及原则2.4 考点十&#xff1a;调度方式与调度算法 一、前言&#x1f680;…

排序(冒泡排序、选择排序、插入排序、希尔排序)-->深度剖析(一)

欢迎来到我的Blog&#xff0c;点击关注哦&#x1f495; 前言 排序是一种基本的数据处理操作&#xff0c;它涉及将一系列项目重新排列&#xff0c;以便按照指定的标准&#xff08;通常是数值大小&#xff09;进行排序。在C语言中&#xff0c;排序算法是用来对元素进行排序的一系…

FPGA 690T NVME高速存储设计

高速存储设计会有各种需求的考虑&#xff0c;那么对应的方案也不完全相同&#xff0c;这篇文章出一期纯FPGA实现的高速存储方案。用纯fpga实现高速存储板卡有易国产化&#xff0c;功耗低和体积小等特点&#xff0c;缺点就是灵活性不是很强&#xff0c;实现标准ext4和nfs文件系统…

数据仓库建模基础理论-01-为什么需要数据建模?

一、什么是数据模型&#xff1f; 数据模型是数据库的基础结构&#xff0c;用于描述和组织数据的方式。 它不仅是数据库的底层结构&#xff0c;还是一个概念性工具&#xff0c;帮助理解数据的含义和关系。 数据模型包括数据本身、数据之间的关系、数据的语义&#xff08;含义和…

C++ | Leetcode C++题解之第206题反转链表

题目&#xff1a; 题解&#xff1a; class Solution { public:ListNode* reverseList(ListNode* head) {if (!head || !head->next) {return head;}ListNode* newHead reverseList(head->next);head->next->next head;head->next nullptr;return newHead;} …

一秒记单词:音通义通,一秒牢记

一秒记单词&#xff0c;从小学到高中&#xff0c;一秒牢记 一、小学生记单词&#xff0c;快速突破 1.1 好的开始&#xff0c;是成功的一半 sun n.太阳 【通】尚 moon n.月亮 【通】母恩 mother n.母亲&#xff0c;妈 【通】妈汁 sea n.海&#xff0c;大海 【通】细 sand …

【MySQL基础篇】SQL指令:DQL及DCL

1、DQL DQL - 介绍 DQL英文全称是Data Query Language(数据查询语言)&#xff0c;数据查询语言&#xff0c;用来查询数据表中的记录。&#xff08;在MySQL中应用是最为广泛的&#xff09; 查询关键字&#xff1a;SELECT DQL - 语法 SELECT 字段列表 FROM 表名列表 WHER…

【人工智能学习之图像操作(六)】

【人工智能学习之图像操作&#xff08;六&#xff09;】 Hough变换直线检测圆检测 图像分割 Hough变换 在图像处理中&#xff0c;霍夫变换用来检测任意能够用数学公式表达的形状&#xff0c;即使这个形状被破坏或者有点扭曲 直线检测 import cv2 import numpy as np image …

利用微信开放标签<wx-open-launch-weapp>在H5中跳转微信小程序报错完美的解决方案

一、报错&#xff1a; [WXTAG] [JSCORE] The slot <template> or <script type"text/wxtag-template"> of <wx-open-launch-weapp> is missing 二、源码 官方源代码如下&#xff0c;<script type"text/wxtag-template"></sc…