?
????????Muduo網絡庫:底層實質上為Linux的epoll + pthread線程池,且依賴boost庫。 muduo的網絡設計核心為一個線程一個事件循環,有一個main Reactor負載accept連接,然后把連接分發到某個sub Reactor(采用輪詢的方式來選擇sub Reactor),該連接的所用操作都在那個sub Reactor所處的線程中完成。多個連接可能被分派到多個線程中,以充分利用CPU,Reactor poll的大小是固定的,根據CPU的數目確定。如果有過多的耗費CPU I/O的計算任務,可以提交到創建的ThreadPool線程池中專門處理耗時的計算任務。
1、 muduo網絡庫實例
muduo網絡庫實質為: epoll + 線程池,優點是能夠將網絡I/O的代碼和業務代碼分開。 而業務代碼主要分為:用戶的連接和斷開、用戶的可讀寫事件兩類。至于什么時候發生這些事件,由網絡庫進行上報,如何監聽這些事件,都是網絡庫所封裝好的,我們就可以快速進行項目開發。
muduo給用戶提供了兩個主要的類:
1、TcpServer:用于編寫服務器程序。
2、TcpClient:用于編寫客戶端程序。
如何配置muduo網絡庫請參考:?寫文章-CSDN創作中心
?muduo網絡庫服務器編程
????????基于muduo網絡庫開發服務器程序
- 組合TcpServer對象
- 創建EventLoop事件循環對象的指針
- 明確TcpServer構造函數需要什么參數,輸出ChatServer的參數
- 在當前服務器類的構造函數當中,注冊處理連接的回調函數和處理讀寫事件的回調函數
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <iostream>
#include <functional>
#include <string>
using namespace std;
using namespace muduo;
using namespace muduo::net;
using namespace placeholders;class ChatServer
{
public:ChatServer(EventLoop *loop,const InetAddress &serverAddr,const string &nameArg): _server(loop, serverAddr, nameArg), _loop(loop){// 注冊連接回調_server.setConnectionCallback(std::bind(&ChatServer::onConnection, this, _1));// 注冊消息回調_server.setMessageCallback(std::bind(&ChatServer::onMessage, this, _1, _2, _3));// 設置線程數量_server.setThreadNum(4); // 4個IO線程}void start(){_server.start();}private:// 處理連接void onConnection(const TcpConnectionPtr &conn){if (conn->connected()){cout << conn->peerAddress().toIpPort() << " -> "<< conn->localAddress().toIpPort() << " state : online " << endl;}else{cout << conn->peerAddress().toIpPort() << " -> " << conn->localAddress().toIpPort() << " state : offline " << endl;}}// 處理消息void onMessage(const TcpConnectionPtr &conn, Buffer *buffer, Timestamp time){string buf = buffer->retrieveAllAsString();cout << "recv data: " << buf << " time: " << time.toString() << endl;conn->send(buf); // 回顯消息}TcpServer _server;EventLoop *_loop;
};int main()
{EventLoop loop;InetAddress addr("127.0.0.1", 9898); // 監聽 127.0.0.1:9898ChatServer server(&loop, addr, "ChatServer");server.start(); // 啟動服務器loop.loop(); // 事件循環return 0;
}
?????????上面的代碼簡單的使用了muduo網絡庫實現了一個回顯服務器,我們可以在linux系統終端中使用telnet命令讓客戶端連接。
2、muduo網絡庫原理
????????Muduo 基于 Reactor 模式,核心是事件驅動。以下是其工作流程:
啟動服務器:
????????創建一個 EventLoop 實例作為主循環。
????????創建一個 TcpServer 實例,設置回調函數(連接、消息處理)。
????????調用 loop.loop() 開始事件循環。
事件監聽:
????????主線程監聽新連接。
????????每當有新連接到來,將其分配到工作線程處理。
事件分發與處理:
????????EventLoop 監聽事件,通過 Poller 檢測就緒的文件描述符。
????????調用 Channel 的回調函數處理事件。
數據收發與連接管理:
????????使用 TcpConnection 提供的接口收發數據。
????????在連接斷開時,自動清理資源。
3、經典的服務器設計模式Reactor模式
????????服務端程序架構基本上是一個大的while循環,程序阻塞在accept或poll函數上,等待被監控的socket描述符上出現預期的事件。事件到達后,accept或poll函數的阻塞解除,程序向下執行,根據socket描述符上出現的事件,執行read、write或錯誤處理。
整體架構如下圖所示:
????????muduo的軟件架構采用的也是Reactor模式,只是整個模式被分成多個類,并且支持以線程池的方式實現多線程并發處理,所以顯得有些復雜。整體架構如下圖所示:?