高級IO_多路轉接之ET模式Reactor

文章目錄

  • Reactor是什么?
    • LT模式 VS ET模式
  • 示例代碼


提示:以下是本篇文章正文內容,下面案例可供參考

Reactor是什么?

Reactor模式是一種事件驅動的并發模型,它通過將事件處理邏輯與事件分發機制解耦,實現高性能、可擴展的并發處理。Reactor模式適用于大量短時連接或需要高效I/O處理的場景,如Web服務器、聊天服務器等。

今天我們所實現的Reactor是基于ET模式下的多路轉接模式。

LT模式 VS ET模式

以我們的epoll為例,我們的epoll默認是LT模式。
LT模式:只要有事件就緒,就會不斷提醒。
ET模式:只有事件從無到有,從少到多的情況,才會提醒一次

所以對于ET模式而言,就需要逼服務器一次性將所有緩沖區數據全部讀完,也算是逼著你效率提高。 而只提醒一次也是高效的表現。

示例代碼

#include "Epoll.hpp"
#include "Socket.hpp"
#include <vector>
#include <functional>
#include <unordered_map>
#include "Common.hpp"
#include "Calculator.hpp"class Connection;
class ReactorServer;using func_t = std::function<void(std::shared_ptr<Connection>)>;
const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8080;#define EVENT_IN (EPOLLIN | EPOLLET)
#define EVENT_OUT (EPOLLOUT | EPOLLET)void SetNonBlock(int fd)
{int fl = fcntl(fd, F_GETFL);if (fl < 0){// 獲取失敗perror("F_GETFD Error");return;}int n = fcntl(fd, F_SETFL, fl | O_NONBLOCK);if (n < 0){perror("Set Nonblock Error");}else{lg(Info, "Set Nonblock Succeed, Fd: %d", fd);// std::cout << "Fd:" << fd << " ,set nonblock done" << std::endl;}
}class Connection : public nocopy
{
public:Connection(int sockfd, ReactorServer *reactor_server): _sockfd(sockfd), _reactor_server(reactor_server) {}void SetHandle(func_t recv_cb, func_t send_cb, func_t except_cb){_recv_cb = recv_cb;_send_cb = send_cb;_except_cb = except_cb;}int Getfd(){return _sockfd;}std::string &GetInBuffer(){return _inbuffer;}std::string &GetOutBuffer(){return _outbuffer;}~Connection() {}private:int _sockfd;std::string _inbuffer;std::string _outbuffer;ReactorServer *_reactor_server;public:func_t _recv_cb;func_t _send_cb;func_t _except_cb;
};class ReactorServer
{
private:const int num = 128;public:ReactorServer(uint16_t port, func_t handle_message): _port(port), _listensock(new Socket), _epoller(new Epoller), _handle_message(handle_message) {}void EnableEvent(int fd, bool recv, bool send){int events = 0;events |= (recv ? EVENT_IN : 0);events |= (send ? EVENT_OUT : 0);_epoller->EpollerUpdate(EPOLL_CTL_MOD, fd, events);}void Accepter(std::shared_ptr<Connection> connection){while (true){int newsock = _listensock->Accept();if (newsock < 0){if (errno == EWOULDBLOCK){break;}else if (errno == EINTR){continue;}lg(Warning, "Accept Error...");break;}AddConnetion(newsock, EVENT_IN, std::bind(&ReactorServer::Recver, this, std::placeholders::_1),std::bind(&ReactorServer::Sender, this, std::placeholders::_1),std::bind(&ReactorServer::Excepter, this, std::placeholders::_1));}}void Recver(std::shared_ptr<Connection> connection){int fd = connection->Getfd();while (true){char buffer[1024];memset(buffer, 0, sizeof buffer);int n = recv(connection->Getfd(), buffer, sizeof buffer - 1, 0);if (n > 0){connection->GetInBuffer() += buffer;std::cout << connection->GetInBuffer();}else if (n < 0){if (errno == EWOULDBLOCK)break;else if (errno == EINTR)continue;lg(Warning, "Read Error...");connection->_except_cb(connection);return;}else{lg(Info, "Foreign Host Closed...");connection->_except_cb(connection);return;}}_handle_message(connection);}void Sender(std::shared_ptr<Connection> connection){int fd = connection->Getfd();std::string &mes = connection->GetOutBuffer();while (1){int n = send(fd, mes.c_str(), mes.size(), 0);if (n < 0){if (errno == EWOULDBLOCK){break;}else if (errno == EINTR){continue;}connection->_except_cb(connection);return;}if (n == 0){break;}mes.erase(0, n);if (mes.empty()){break;}}if (!mes.empty()){EnableEvent(fd, true, true);}else{EnableEvent(fd, true, false);}}void Excepter(std::shared_ptr<Connection> connection){int fd = connection->Getfd();// 1.先從內核中移除_epoller->EpollerUpdate(EPOLL_CTL_DEL, fd, 0);// 2.從_connections中移除_connections.erase(fd);// 3.關閉sockfdclose(fd);lg(Info, "Sockfd: %d Closed...", fd);}void AddConnetion(int fd, int events, func_t recv_cb, func_t send_cb, func_t except_cb){// 1.設置非阻塞SetNonBlock(fd);// 2.創建新connectionstd::shared_ptr<Connection> newcon(new Connection(fd, this));newcon->SetHandle(recv_cb, send_cb, except_cb);// 3.插入到_connetcions_connections[fd] = newcon;// 4.放入內核_epoller->EpollerUpdate(EPOLL_CTL_ADD, fd, events);}void Init(){_epoller->Init();_listensock->Init();_listensock->Bind(AF_INET, default_ip, _port);_listensock->Listen();AddConnetion(_listensock->_sockfd, EVENT_IN, std::bind(&ReactorServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);}bool IsConnectionSafe(int fd){return _connections.find(fd) == _connections.end() ? false : true;}void Start(){struct epoll_event recvs[num];while (1){int n = _epoller->EpollWait(recvs, num, -1);if (n > 0){// std::cout << "檢測到事件 n:" << n << std::endl;for (int i = 0; i < n; i++){int fd = recvs[i].data.fd;int events = recvs[i].events;if (events & EPOLLERR){events |= EPOLLIN;}if (events & EPOLLHUP){events |= EPOLLIN;}if ((events & EPOLLIN) && IsConnectionSafe(fd)){if (_connections[fd]->_recv_cb){_connections[fd]->_recv_cb(_connections[fd]);}}if ((events & EPOLLOUT) && IsConnectionSafe(fd)){if (_connections[fd]->_send_cb){_connections[fd]->_send_cb(_connections[fd]);}}}}else if (n == 0){lg(Info, "Time Out...");}else{if (errno == EWOULDBLOCK)continue;lg(Warning, "Epoll error...");std::cout << "errno:" << errno << " strerror:" << strerror(errno) << std::endl;exit(1);}}}~ReactorServer() {}private:std::unique_ptr<Socket> _listensock;std::unique_ptr<Epoller> _epoller;std::unordered_map<int, std::shared_ptr<Connection>> _connections;uint16_t _port;func_t _handle_message;
};
#include "ReactorServer.hpp"void default_HandleMessage(std::shared_ptr<Connection> connection)
{
//根據服務器的服務內容編寫此函數
//例如我這里想做一個計算器服務Calculator cal;std::string &inbuffer = connection->GetInBuffer();while (!inbuffer.empty()){std::string mes;int type;if (!CheckType(inbuffer, &type)){// 報文內容出現問題inbuffer = "";break;}if (type == 1){IntHandle(inbuffer, &mes);}else if (type == 2){DoubleHandle(inbuffer, &mes);}else{lg(Warning, "Type Error, type: %d ...", type);}connection->GetOutBuffer() += mes;connection->_send_cb(connection);}
}int main(int argc, char *argv[])
{if (argc != 2){std::cout << "Usage: ./selectServer port[8000-9000]" << std::endl;}ReactorServer ser(atoi(argv[1]), func_t(default_HandleMessage));ser.Init();ser.Start();return 0;
}

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

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

相關文章

maven如何處理依賴沖突的問題?

Maven是一個強大的Java項目管理工具&#xff0c;它使用一個名為pom.xml的文件來管理項目的構建過程和依賴關系。當項目中出現依賴沖突時&#xff0c;Maven使用一系列策略來解決這些問題。以下是Maven處理依賴沖突的一些常見方法&#xff1a; 1. 最近優先策略&#xff1a; -…

tensorflow之欠擬合與過擬合,正則化緩解

過擬合泛化性弱 欠擬合解決方法&#xff1a; 增加輸入特征項 增加網絡參數 減少正則化參數 過擬合的解決方法&#xff1a; 數據清洗 增大訓練集 采用正則化 增大正則化參數 正則化緩解過擬合 正則化在損失函數中引入模型復雜度指標&#xff0c;利用給w增加權重&#xff0c;…

點線面推進未來智造

如今&#xff0c;寧波擁有門類齊全的制造業體系&#xff0c;形成了以石油化工、汽車及零部件、電工電器、紡織服裝等為支柱的產業集群。 寧波工業的發展并非一蹴而就&#xff0c;藍卓總經理譚彰詳細解讀了寧波制造業的發展歷程與當下目標&#xff0c;從工業小市到工業大市、工業…

基于Matlab和Python泰勒圖的繪制

一、泰勒圖介紹 泰勒圖:泰勒圖1常用于評價模型的精度,常用的精度指標有相關系數,標準差以及均方根誤差(RMSE)。一般而言,泰勒圖中的散點代表模型,輻射線代表相關系數,橫縱軸代表標準差,而虛線代表均方根誤差。泰勒圖一改以往用散點圖這種只能呈現兩個指標來表示模型精度…

Qt使用筆記1(智能指針,deleteLater,多屏)

1、Qt智能指針 1.1、QPointer &#xff1a;解決野指針問題&#xff0c;必須是QObject對象。 1.2、QScopedPoint&#xff1a;作用域指針&#xff0c;出作用域自動釋放。 1.3、QScopedArrayPoint&#xff1a;作用域數組指針&#xff0c;出作用域自動釋放數組。 1.4、QSharedP…

RedHat運維-Ansible自動化運維基礎20-從ansible-galaxy下載role

1. 社區管理的role倉庫&#xff1a;___________________________________&#xff1b; 2. 社區管理的role倉庫&#xff1a;___________________________________&#xff1b; 3. 社區管理的role倉庫&#xff1a;___________________________________&#xff1b; 4. 在ansible …

Python數據結構的庫之Fuk使用詳解

概要 fuk 是一個用于處理 Python 數據結構的庫,全稱為 "Fast and Uncomplicated Kit"。它提供了一系列高效、簡潔的數據結構實現,以及對 Python 內置數據結構的擴展。通過使用 fuk,開發者可以更加方便地處理列表、集合、字典等數據類型,提高代碼的執行效率和可讀…

vite+vue3拍照上傳到nodejs服務器

一:效果展示: 拍照效果 二:Nodejs后端接口代碼: 三:前端完整代碼:

Vue基礎--v-model/v-for/事件屬性/偵聽器

目錄 一 v-model表單元素 1.1 v-model綁定文本域的value 1.1.1 lazy屬性&#xff1a;光標離開再發請求 1.1.2 number屬性&#xff1a;如果能轉成number就會轉成numer類型 1.1.3 trim屬性&#xff1a;去文本域輸入的前后空格 1.2v-model綁定單選checkbox 1.3代碼展示 二 …

esp8266+micropython+irsend紅外發射調試記錄

在網上搜索esp8266micropython的紅外發射庫&#xff0c;沒找到&#xff0c;發現 接收庫是有的&#xff0c;可以參考&#xff1a;基于MicroPython的ESP8266連接外設IO&#xff08;二&#xff09;_micropython 紅外接收-CSDN博客 可惜沒有發射&#xff0c;很不方便。 這里都有介…

PHP財務記賬管理系統小程序源碼

理財小能手必備&#xff01;揭秘財務記賬管理系統的魔力? &#x1f31f; 引入篇&#xff1a;告別糊涂賬&#xff0c;擁抱財務自由 你是否曾為月底的賬單頭疼不已&#xff1f;是否覺得自己的錢總是莫名其妙地消失&#xff1f;別擔心&#xff0c;財務記賬管理系統來拯救你的錢…

【機器學習】必會數學知識:一文掌握數據科學核心數學知識點(下),收藏~

核心數學知識點 1、引言2、數據科學必會數學知識2.13 K均值聚類2.14 決策樹2.15 隨機森林2.16 梯度下降2.17 隨機梯度下降&#xff08;SGD&#xff09;2.18 卷積2.19 拉普拉斯變換2.20 傅里葉變換2.21 信息論2.22 時間序列分析2.23 生成模型與判別模型2.24 支持向量機&#xff…

git merge 分支回退

1. 使用git merge --abort&#xff08;如果合并正在進行中&#xff09; git merge --abort2. 使用git reset&#xff08;合并已經提交&#xff09; 硬重置&#xff08;--hard&#xff09;會丟棄所有合并后的更改&#xff0c;并將HEAD指向合并前的提交。這是最徹底的方式&…

DDOS 攻擊原理

DDoS攻擊的基本原理 資源耗盡&#xff1a;攻擊者通過發送大量的請求或數據包&#xff0c;耗盡目標系統的資源&#xff08;如帶寬、CPU、內存等&#xff09;&#xff0c;使其無法處理正常的用戶請求。 分布式攻擊&#xff1a;與傳統的DoS&#xff08;拒絕服務&#xff09;攻擊不…

Java-面向對象基礎

在面向對象編程&#xff08;Object-Oriented Programming, OOP&#xff09;中&#xff0c;類&#xff08;Class&#xff09;是一種用來描述對象共同特征的藍圖或模板。它是創建對象的原型&#xff0c;定義了對象可以有的屬性&#xff08;字段&#xff09;和行為&#xff08;方法…

物聯網應用,了解一點 WWAN全球網絡標準

WWAN/蜂窩無線電認證&#xff0c;對跨地區應用場景&#xff0c;特別重要。跟隨全球業務的腳步&#xff0c;我們像大唐先輩一樣走遍全球業務的時候&#xff0c;了解一點全球化的 知識信息&#xff0c;就顯得有那么點意義。 NA &#xff08;北美&#xff09;&#xff1a;美國和加…

OpenSSH漏洞(CVE-2024-6387)

漏洞信息 請參考:OpenSSH遠程代碼執行漏洞 (CVE-2024-6387) 影響范圍 8.5p1 <= OpenSSH < 9.8p1 參考鏈接中內容補充 利用方式 關于OpenSSH漏洞CVE-2024-6387,攻擊者可以利用一個有用的代碼路徑并在正確的時間點上被SIGALRM信號打斷,從而導致sshd(OpenSSH守護…

基于Python的嗶哩嗶哩數據分析系統設計實現過程,技術使用flask、MySQL、echarts,前端使用Layui

背景和意義 隨著互聯網和數字媒體行業的快速發展&#xff0c;視頻網站作為重要的內容傳播平臺之一&#xff0c;用戶量和內容豐富度呈現爆發式增長。本研究旨在設計并實現一種基于Python的嗶哩嗶哩數據分析系統&#xff0c;采用Flask框架、MySQL數據庫以及echarts數據可視化技術…

工控、物聯網、電力行業調試工具大全

工控、物聯網、電力行業調試工具大全 文章目錄 工控、物聯網、電力行業調試工具大全Modbus調試工具MQTT調試工具IEC104/IEC101調試工具IEC61850 調試工具DL/T645 調試工具 Modbus調試工具 Modbus 是一種用于工業自動化系統中的通信協議&#xff0c;最早由 Modicon&#xff08;…

信號111

2、核心轉儲 當進程出現魔種異常的時候&#xff0c;是否有OS將當前進程在內存中的相關核心數據&#xff0c;轉存到磁盤中&#xff01; 一般而言云服務器的核心轉儲功能是關閉的。 3、驗證進程等待中的core dump標記位。 4、為什么生產環境一般都要關閉 core dump 系統調用接口…