[分布式網絡通訊框架]----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.pswp.cn/diannao/37982.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/37982.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/37982.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LLVM AliasAnalysis別名分析 TBAA TypeBasedAliasAnalysis

一、什么是別名分析 Alias Analysis (又名 Pointer Analysis)是用于確定兩個指針是否指向內存中的同一對象&#xff0c;這里有很多不同的別名分析算法&#xff0c;分為幾種類型&#xff1a;流敏感vs流非敏感、上下文敏感vs上下文非敏感、域敏感vs域非敏感、基于一致性的vs基于…

單片機學習(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…

linux高級編程(進程)(2)

父子進程的關系&#xff1a; 子進程是父進程的副本。子進程獲得父進程數據段&#xff0c;堆&#xff0c;棧&#xff0c;正文段共享。&#xff08;子分配了一塊新的內存&#xff0c;但是代碼段指向父進程&#xff0c;也就是說不論幾個子進程都只有一個code段&#xff09; …

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…

【計算機網絡】HTTPS——更安全的HTTP通信(個人筆記)

學習日期&#xff1a;2024.6.26 內容摘要&#xff1a;HTTPS存在的意義、特點和工作方式 HTTP的缺點——易竊聽、偽裝、篡改 在Web及網絡基礎中&#xff0c;我們已經知道了網頁是怎么打開的&#xff0c;HTTP確實是一個相當優秀和方便的協議&#xff0c;但HTTP也有很多不足&…

【操作系統期末速成】 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文件系統…

計算機的錯誤計算(十六)

摘要 計算機的錯誤計算&#xff08;十五&#xff09;中歷史事件給我們的啟示或警示。 計算機的錯誤計算&#xff08;十五&#xff09;介紹了歷史上發生的一些事件。從這些事件我們可以得到一些啟示或警示。 若不是油氣平臺的沉沒&#xff0c;設計者會得出精度低了嗎&#x…

信息盲盒系統設計

信息盲盒系統是一種結合了隨機性和趣味性的信息傳遞和接收方式&#xff0c;類似于實體盲盒的概念&#xff0c;但在數字領域應用。這種系統通常用于增加用戶參與度、提升用戶體驗或作為營銷策略的一部分。設計一個信息盲盒系統需要考慮以下幾個關鍵要素&#xff1a; 1. 定義目標…

數據倉庫建模基礎理論-01-為什么需要數據建模?

一、什么是數據模型&#xff1f; 數據模型是數據庫的基礎結構&#xff0c;用于描述和組織數據的方式。 它不僅是數據庫的底層結構&#xff0c;還是一個概念性工具&#xff0c;幫助理解數據的含義和關系。 數據模型包括數據本身、數據之間的關系、數據的語義&#xff08;含義和…