网络编程模型 / Reactor
之前一直不理解 Reactor 模型的含義,后來在知乎上看見了一個 demo,再結(jié)合文字終于理解什么是 Reactor 模型了,這里分享給大家。
一、介紹
網(wǎng)絡(luò)編程模型通常有如下幾種:Reactor,Proactor,Asynchronous Completion Token and Acceptor-Connector。本文主要對最主流的 Reactor模型進行介紹。
通常網(wǎng)絡(luò)編程模型處理的主要流程如下
initiate => receive => demultiplex => dispatch => process events
I/O 多路復(fù)用可以用作并發(fā)事件驅(qū)動(event-driven)程序的基礎(chǔ),即整個事件驅(qū)動模型是一個狀態(tài)機,包含了狀態(tài)(state), 輸入事件(input-event), 狀態(tài)轉(zhuǎn)移(transition), 狀態(tài)轉(zhuǎn)移即狀態(tài)到輸入事件的一組映射。通過 I/O 多路復(fù)用的技術(shù)檢測事件的發(fā)生,并根據(jù)具體的事件(通常為讀寫),進行不同的操作,即狀態(tài)轉(zhuǎn)移。
Reactor 模式是一種典型的事件驅(qū)動的編程模型,Reactor 逆置了程序處理的流程,其基本的思想即為 Hollywood Principle — 'Don't call us, we'll call you'。
普通的函數(shù)處理機制為:調(diào)用某函數(shù) -> 函數(shù)執(zhí)行, 主程序等待阻塞 -> 函數(shù)將結(jié)果返回給主程序 -> 主程序繼續(xù)執(zhí)行。
Reactor 事件處理機制為:主程序?qū)⑹录约皩?yīng)事件處理的方法在 Reactor 上進行注冊,如果相應(yīng)的事件發(fā)生,Reactor 將會主動調(diào)用事件注冊的接口,即 回調(diào)函數(shù)。libevent 封裝了 epoll 并注冊相應(yīng)的事件(I/O讀寫,時間事件,信號事件)以及回調(diào)函數(shù),實現(xiàn)的事件驅(qū)動的框架。
二、架構(gòu)
1、事件(事件源)
linux 上為文件描述符,handler 即為注冊在特定事件上的程序,事件發(fā)生通常在 linux 下為 I/O 事件,由操作系統(tǒng)觸發(fā)。
2、Reactor (反應(yīng)器)
事件管理的接口,內(nèi)部使用 event demultiplexer 注冊、注銷事件;并運行事件循環(huán),當(dāng)有事件進入"就緒"狀態(tài)時,調(diào)用注冊事件的回調(diào)函數(shù)處理事件。
class Reactor { public:int register_handler(EventHandler *pHandler, int event);int remove_handler(EventHandler *pHandler, int event);void handle_events(timeval *ptv); }3、Event demultiplexer(事件多路分發(fā)機制)
通常是由操作系統(tǒng)提供的 I/O 多路復(fù)用的機制,例如 select,epoll。程序首先將 handler(事件源)以及對應(yīng)的事件注冊到 event demultiplexer 上;當(dāng)有事件到達時,event demultiplexer 就會發(fā)出通知,通知 Reactor 調(diào)用事件處理程序進行處理。
4、Event Handler(事件處理程序)
事件處理程序提供了一組接口,在 Reactor 相應(yīng)的事件發(fā)生時調(diào)用,執(zhí)行相應(yīng)的事件處理,通常會綁定一個有效的 handler 。
class Event_Handler { public:// events maybe read/write/timeout/close .etcvirtual void handle_events(int events) = 0;virtual HANDLE get_handle() = 0; }三、實現(xiàn)
#include <sys/epoll.h> #include <unistd.h> #include <iostream> #include <array> #include <unordered_map>typedef std::string EventType; class MyEventDemultiplexer { public:static const int NO_FLAGS = 0;static const int BLOCK_INDEFINITELY = -1;static const int MAX_EVENTS = 5;MyEventDemultiplexer(){fileDescriptor = epoll_create1(NO_FLAGS);event.data.fd = STDIN_FILENO;//設(shè)置epoll event 為 EPOLLIN (對應(yīng)文件描述符可讀), EPOLLPRI (對應(yīng)文件描述符有緊急事件可讀)event.events = EPOLLIN | EPOLLPRI;}~MyEventDemultiplexer(){close(fileDescriptor);}int wait(){return epoll_wait(fileDescriptor, events.data(), MAX_EVENTS, BLOCK_INDEFINITELY);}int control(){return epoll_ctl(fileDescriptor, EPOLL_CTL_ADD, STDIN_FILENO, &event);}private:int fileDescriptor;struct epoll_event event;std::array<epoll_event, MAX_EVENTS> events{}; };class MyEventHandler { public:int handle_event(EventType et){std::cout << "Event Handler: " << et << std::endl;return 0;} };class Reactor { public:Reactor(){m_event_demultiplexer.control();}void addHandler(std::string event, MyEventHandler callback){handlers.emplace(std::move(event), std::move(callback));}void run(){while (true){int numberOfEvents = wait();for (int i = 0; i < numberOfEvents; ++i){std::string input;std::getline(std::cin, input);try{// 根據(jù)的具體的事件去找對應(yīng)的handler,并執(zhí)行相應(yīng)的操作handlers.at(input).handle_event(EventType(input));}catch (const std::out_of_range &e){std::cout << "no handler for " << input << std::endl;}}}}private:std::unordered_map<std::string, MyEventHandler> handlers{};MyEventDemultiplexer m_event_demultiplexer;int wait(){int numberOfEvents = m_event_demultiplexer.wait();return numberOfEvents;} };int main() {Reactor reactor;reactor.addHandler("a", MyEventHandler{});reactor.addHandler("b", MyEventHandler{});reactor.run(); }結(jié)果:
a Event Handler: a b Event Handler: b c no handler for c轉(zhuǎn)載于:https://zhuanlan.zhihu.com/p/93612337
(SAW:Game Over!)
?
總結(jié)
以上是生活随笔為你收集整理的网络编程模型 / Reactor的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JWT 说明
- 下一篇: linux / 命令行 / LD_DEB