[muduo網絡庫]-muduo庫TcpServer類解析

本貼用于記錄muduo庫的學習過程,以下是關于TcpServer的個人理解。

TcpServer內含Acceptor、threadpool等類,算是把主線程所有要做的事封裝了起來。

重要成員變量

EventLoop *loop_; // baseloop 用戶自定義的loopconst std::string ipPort_;const std::string name_;std::unique_ptr<Acceptor> acceptor_; // 運行在mainloop 任務就是監聽新連接事件std::shared_ptr<EventLoopThreadPool> threadPool_; // one loop per threadConnectionCallback connectionCallback_;       //有新連接時的回調MessageCallback messageCallback_;             // 有讀寫事件發生時的回調WriteCompleteCallback writeCompleteCallback_; // 消息發送完成后的回調ThreadInitCallback threadInitCallback_; // loop線程初始化的回調int numThreads_;//線程池中線程的數量。std::atomic_int started_;int nextConnId_;ConnectionMap connections_; // 保存所有的連接

loop_:代表baseloop。

acceptor_:用來監聽和接收新連接。

threadPool_:用于管理線程。

started_:是否啟動的標志。用atomic_int定義為了維護線程安全。

nextConnId:表示是第幾個連接。

connections_:保存所有的tcpconnection指針。

重要成員函數

TcpServer::TcpServer(EventLoop *loop,const InetAddress &listenAddr,const std::string &nameArg,Option option): loop_(CheckLoopNotNull(loop)), ipPort_(listenAddr.toIpPort()), name_(nameArg), acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)), threadPool_(new EventLoopThreadPool(loop, name_)), connectionCallback_(), messageCallback_(), nextConnId_(1), started_(0)
{// 當有新用戶連接時,Acceptor類中綁定的acceptChannel_會有讀事件發生,執行handleRead()調用TcpServer::newConnection回調acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));
}

構造函數,acceptor和threadpool都是new出來的,但是eventloop是外部輸入的,為什么這樣設計?我感覺是為了讓生命周期更清晰,loop由外部輸入,結束時tcpserver先析構,loop再析構,這樣不會存在server調用不存在loop的情況。希望知道的朋友可以告訴我。

void TcpServer::setThreadNum(int numThreads)
{int numThreads_=numThreads;threadPool_->setThreadNum(numThreads_);
}

設置要開啟多少線程。

void TcpServer::start()
{if (started_.fetch_add(1) == 0)    // 防止一個TcpServer對象被start多次{threadPool_->start(threadInitCallback_);    // 啟動底層的loop線程池loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_.get()));}
}

tecpserver的啟動函數。fetch_add(1)將started_原子性地+1,并返回舊值。

void TcpServer::newConnection(int sockfd, const InetAddress &peerAddr)
{// 輪詢算法 選擇一個subLoop 來管理connfd對應的channelEventLoop *ioLoop = threadPool_->getNextLoop();char buf[64] = {0};snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_);++nextConnId_;  // 這里沒有設置為原子類是因為其只在mainloop中執行 不涉及線程安全問題std::string connName = name_ + buf;LOG_INFO("TcpServer::newConnection [%s] - new connection [%s] from %s\n",name_.c_str(), connName.c_str(), peerAddr.toIpPort().c_str());// 通過sockfd獲取其綁定的本機的ip地址和端口信息sockaddr_in local;::memset(&local, 0, sizeof(local));socklen_t addrlen = sizeof(local);if(::getsockname(sockfd, (sockaddr *)&local, &addrlen) < 0){LOG_ERROR("sockets::getLocalAddr");}InetAddress localAddr(local);TcpConnectionPtr conn(new TcpConnection(ioLoop,connName,sockfd,localAddr,peerAddr));connections_[connName] = conn;// 下面的回調都是用戶設置給TcpServer => TcpConnection的,至于Channel綁定的則是TcpConnection設置的四個,handleRead,handleWrite... 這下面的回調用于handlexxx函數中conn->setConnectionCallback(connectionCallback_);conn->setMessageCallback(messageCallback_);conn->setWriteCompleteCallback(writeCompleteCallback_);// 設置了如何關閉連接的回調conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1));ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
}

當acceptor的channel觸發事件,進行這個函數回調。getsockname得到此連接對應的本地端口。我們已經獲得了連接的socket,接收和發送信息都通過這個socket,為什么還要tcpconnection保存對方的地址peerAddr。比如有人進攻你的網站,你需要一個黑白名單,就可以通過這個peeraddr來設置。

void TcpServer::removeConnection(const TcpConnectionPtr &conn)
{loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
}void TcpServer::removeConnectionInLoop(const TcpConnectionPtr &conn)
{LOG_INFO("TcpServer::removeConnectionInLoop [%s] - connection %s\n",name_.c_str(), conn->name().c_str());connections_.erase(conn->name());EventLoop *ioLoop = conn->getLoop();ioLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
}

當要移除一個連接時,先將removeConnectionInLoop函數放入所屬線程等待執行,erase移除在tcpserver里的conn指針,由于conn也是一個shared_ptr(由shared_from_this()傳入),所以不會直接銷毀,在啟動connectiondestroyed函數,對conn內的事件取消監聽,結束后自動銷毀TCPConnection。

TcpServer::~TcpServer()
{for(auto &item : connections_){TcpConnectionPtr conn(item.second);item.second.reset();    // 把原始的智能指針復位 讓棧空間的TcpConnectionPtr conn指向該對象 當conn出了其作用域 即可釋放智能指針指向的對象// 銷毀連接conn->getLoop()->runInLoop(std::bind(&TcpConnection::connectDestroyed, conn));}
}

當tcpserver要析構時,遍歷connections_,reset用于將該智能指針設置為空,再銷毀該tcpconnection。


以上就是我對TcpServer類的理解,歡迎大家交流討論。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/95428.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/95428.shtml
英文地址,請注明出處:http://en.pswp.cn/web/95428.shtml

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

相關文章

工作兩年,最后從css轉向tailwind了!

菜鳥上班已經兩年了&#xff0c;從一個對技術充滿熱情的小伙子&#xff0c;變成了一個職場老鳥了。自以為自己在不停的學習&#xff0c;但是其實就是學一些零碎的知識點&#xff0c;比如&#xff1a;vue中什么東西沒見過、js什么特性沒用過、css新出了個啥 …… 菜鳥感覺自己也…

macOS 更新后找不到鑰匙串訪問工具的解決方案

macOS 更新后找不到鑰匙串訪問工具的解決方案 隨著macOS的不斷更新&#xff0c;一些系統工具的位置可能會發生變化&#xff0c;給用戶帶來不便。鑰匙串訪問&#xff08;Keychain Access&#xff09;是macOS中一個非常重要的工具&#xff0c;用于管理密碼、證書等敏感信息。最近…

深入理解Go 與 PHP 在參數傳遞上的核心區別

$run_return_data []; $ret $this->handleData($event_req_info, $run_return_data); public function handleData($event_req_info, &$run_return_data): array {$run_return_data [ //使用引用變量返回數據shop_id > $shop_id,request_id > $request_…

【Dify智能體】2025 最新版Linux部署Dify教程(Ubuntu)

一、前言 Dify 是一款開源的智能體工作流平臺,可以用來快速構建 AI 應用。相比手動搭建復雜的依賴環境,Docker Compose 部署方式更簡單、更快速、更穩定。本文將一步步帶你在 Ubuntu 22.04 + Docker Compose v2 上安裝 Dify,并給出常見問題與優化方案。 ps:如果還沒有安裝…

基礎思想:動態規劃與貪心算法

一、動態規劃核心思想&#xff1a;將復雜問題分解為相互重疊的子問題&#xff0c;通過保存子問題的解來避免重復計算&#xff08;記憶化&#xff09;。動態規劃需要通過子問題的最優解&#xff0c;推導出最終問題的最優解&#xff0c;因此這種方法特別注重子問題之間的轉移關系…

使用生成對抗網絡增強網絡入侵檢測性能

文章目錄前言一、GAN 模型介紹二、研究方法1.數據集選擇與處理2.IDS 基線模型構建3. GAN 模型設計與樣本生成4.生成樣本質量評估三、實驗評估四、總結前言 網絡入侵檢測系統&#xff08;Network Intrusion Detection System, NIDS&#xff09;在保護關鍵數字基礎設施免受網絡威…

VR森林經營模擬體驗帶動旅游經濟發展

將VR森林經營模擬體驗作為一種獨特的旅游項目&#xff0c;正逐漸成為旅游市場的新熱點。游客們無需長途跋涉前往深山老林&#xff0c;只需在旅游景區的VR體驗中心&#xff0c;戴上VR設備&#xff0c;就能開啟一場奇妙的森林之旅。在虛擬森林中&#xff0c;他們可以盡情探索&…

Vue2存量項目國際化改造踩坑

Vue2存量項目國際化改造踩坑 一、背景 在各類業務場景中&#xff0c;國際化作為非常重要的一部分已經有非常多成熟的方案&#xff0c;但對于一些存量項目則存在非常的改造成本&#xff0c;本文將分享一個的Vue2項目國際化改造方案&#xff0c;通過自定義Webpack插件自動提取中文…

硬件開發(1)—單片機(1)

1.單片機相關概念1.CPU&#xff1a;中央處理器&#xff0c;數據運算、指令處理&#xff0c;CPU性能越高&#xff0c;完成指令處理和數據運算的速度越快核心&#xff1a;指令解碼執行數據運算處理2.MCU&#xff1a;微控制器&#xff0c;集成度比較高&#xff0c;將所有功能集成到…

Elasticsearch面試精講 Day 4:集群發現與節點角色

【Elasticsearch面試精講 Day 4】集群發現與節點角色 在“Elasticsearch面試精講”系列的第四天&#xff0c;我們將深入探討Elasticsearch分布式架構中的核心機制——集群發現&#xff08;Cluster Discovery&#xff09;與節點角色&#xff08;Node Roles&#xff09;。這是構…

微信小程序長按識別圖片二維碼

提示&#xff1a;二維碼圖片才能顯示識別菜單1.第一種方法添加屬性&#xff1a;show-menu-by-longpress添加屬性&#xff1a;show-menu-by-longpress <image src"{{shop.wx_qrcode}}" mode"widthFix" show-menu-by-longpress></image>2.第二種…

智能化數據平臺:AI 與大模型驅動的架構升級

在前面的文章中,我們探討了 存算分離與云原生,以及 流批一體化計算架構 的演進趨勢。這些演進解決了“算力與數據效率”的問題。但在今天,企業在數據平臺上的需求已經從 存儲與計算的統一,逐步走向 智能化與自動化。 尤其是在 AI 與大模型快速發展的背景下,數據平臺正在發…

解鎖 Vue 動畫的終極指南:Vue Bits 實戰進階教程,讓你的Vue動畫比原生動畫還絲滑,以及動畫不生效解決方案。

一條 Splash Cursor 的 10 秒 Demo 視頻曾創下 200 萬 播放量&#xff0c;讓 React Bits 風靡全球。如今&#xff0c;Vue 開發者終于迎來了官方移植版 —— Vue Bits。 在現代 Web 開發中&#xff0c;UI 動效已成為提升用戶體驗的關鍵因素。Vue Bits 作為 React Bits 的官方 Vu…

《微服務協作實戰指南:構建全鏈路穩健性的防御體系》

在微服務架構從“技術嘗鮮”邁向“規模化落地”的進程中&#xff0c;服務間的協作不再是簡單的接口調用&#xff0c;而是涉及超時控制、事務一致性、依賴容錯、配置同步等多維度的復雜博弈。那些潛藏于協作鏈路中的隱性Bug&#xff0c;往往不是單一服務的功能缺陷&#xff0c;而…

STM32F103C8T6的智能醫療藥品存儲柜系統設計與華為云實現

項目開發背景 隨著現代醫療技術的快速發展&#xff0c;藥品的安全存儲與管理成為醫療質量控制中的重要環節。許多藥品對存儲環境的溫濕度具有嚴格的要求&#xff0c;一旦超出允許范圍&#xff0c;藥品的理化性質可能發生改變&#xff0c;甚至失效&#xff0c;直接影響患者的用藥…

python批量調用大模型API:多線程和異步協程

文章目錄 多線程批量調用 基本原理 實現代碼 代碼解析 使用注意事項 異步協程實現批量調用 異步協程實現方式 異步實現的核心原理 多線程 vs 異步協程 選擇建議 多線程批量調用 基本原理 多線程批量調用大模型API的核心思想是通過并發處理提高效率,主要原理包括: 并發請求:…

硬件開發1-51單片機1

一、嵌入式1、概念&#xff1a;以應用為中心&#xff0c;以計算機技術為基礎&#xff0c;軟硬件可裁剪的專用計算機系統以應用為中心&#xff1a;系統設計的起點是 “具體應用場景”&#xff0c;按照應用需求出發以計算機技術為基礎&#xff1a; 硬件技術&#xff1a;嵌…

Redis核心數據類型解析——string篇

Redis的常見數據類型Redis 提供了 5 種數據結構&#xff0c;理解每種數據結構的特點對于 Redis 開發運維?常重要&#xff0c;同時掌握每 種數據結構的常?命令&#xff0c;會在使? Redis 的時候做到游刃有余。預備在正式介紹 5 種數據結構之前&#xff0c;了解?下 Redis 的?…

爬蟲逆向--Day20Day21--扣JS逆向練習【案例4:深證信服務平臺】

一、案例【深證信數據服務平臺】案例地址鏈接&#xff1a;https://webapi.cninfo.com.cn/#/marketDataDate案例爬取鏈接&#xff1a;https://webapi.cninfo.com.cn/api/sysapi/p_sysapi10071.1、入口定位當進行入口定位時&#xff0c;我們首先需要進行查看響應、載荷、請求頭是…

ExcelJS實現導入轉換HTML展示(附源碼可直接使用)

目錄 簡介 開始實踐 難點 文件示例 效果預覽 具體實現 安裝 完整代碼 總結 簡介 在日常工作中&#xff0c;我們可能會遇到需要上傳并展示 Excel 文件的需求&#xff0c;實現文件內容的在線預覽。 這里給大家接收一個組件庫exceljs&#xff0c;這個組件庫進過實踐發現…