參考文獻(xiàn):libevent源碼深度剖析二
這是libevent學(xué)習(xí)過程的一個基礎(chǔ)補(bǔ)充
1 Reactor的事件處理機(jī)制
普通的函數(shù)調(diào)用機(jī)制的流程是這樣的:調(diào)用函數(shù)-函數(shù)執(zhí)行-返回結(jié)果-程序繼續(xù)處理
Reactor則是一種事件驅(qū)動的機(jī)制陨溅,這在C#孝偎,Qt等程序中都有所體現(xiàn)褥蚯,即應(yīng)用程序提供接口注冊到Reactor上漆改,相應(yīng)的事件發(fā)生時诗舰,Reactor自動調(diào)用這個接口,這個接口也被稱為“回調(diào)函數(shù)”祖秒。
2 Reactor模式的優(yōu)點(diǎn)
Reactor模式是編寫高性能網(wǎng)絡(luò)服務(wù)器的必備技術(shù)之一聂喇,它具有如下的優(yōu)點(diǎn):
1)響應(yīng)快,不必為單個同步時間所阻塞儒洛,雖然Reactor本身依然是同步的精耐;
2)編程相對簡單,可以最大程度的避免復(fù)雜的多線程及同步問題琅锻,并且避免了多線程/進(jìn)程的切換開銷卦停;
3)可擴(kuò)展性,可以方便的通過增加Reactor實(shí)例個數(shù)來充分利用CPU資源恼蓬;
4)可復(fù)用性惊完,reactor框架本身與具體事件處理邏輯無關(guān),具有很高的復(fù)用性处硬;
3 Reactor模式框架
使用Reactor框架小槐,必備的幾個組件:事件源,Reactor框架郁油,多路復(fù)用機(jī)制和事件處理程序本股,先來看看Reactor模型的整體框架:
1)事件源
描述符由操作系統(tǒng)提供攀痊,用于識別每一個事件桐腌,如Socket描述符拄显、文 件描述符等。在Linux中案站,它用一個整數(shù)來表示躬审。事件可以來自外部,如來自客戶端 的連接請求蟆盐、數(shù)據(jù)等承边。事件也可以來自內(nèi)部,如定時器事件石挂。
Linux上是一個整數(shù)的描述符博助,Windows上就是Socket或者Handle,程序在指定的句柄上注冊關(guān)心的事件痹愚。
2)event demultiplexer——事件多路分發(fā)機(jī)制
是一個函數(shù)富岳,用來等待一個或多個事件的發(fā)生。調(diào)用者會被阻 塞拯腮,直到分離器分離的描述符集上有事件發(fā)生窖式。Linux的select函數(shù)是一個經(jīng)常被使 用的分離器。
程序首先將其關(guān)心的句柄及事件注冊到event demultiplexer上动壤,當(dāng)有事件到達(dá)時萝喘,event demultiplexer會發(fā)出通知“在已經(jīng)注冊的句柄集中,一個或多個句柄的事件已經(jīng)就緒”琼懊,程序收到通知后阁簸,就可以在非阻塞的情況下對事件進(jìn)行處理了。
3)Reactor——反應(yīng)器
Reactor哼丈,是事件管理的接口启妹,內(nèi)部使用event demultiplexer注冊、注銷事件削祈;并運(yùn)行事件循環(huán)翅溺,當(dāng)有事件進(jìn)入“就緒”狀態(tài)時,調(diào)用注冊事件的回調(diào)函數(shù)處理事件髓抑。
對應(yīng)到libevent中咙崎,就是event_base結(jié)構(gòu)體。
一個典型的Reactor聲明方式:
class Reactor
{
public:
int register_handler(Event_Handler *pHandler, int event);
int remove_handler(Event_Handler *pHandler, int event);
void handle_events(timeval *ptv);
// ...
};
4) Event Handler——事件處理程序
事件處理程序提供了一組接口吨拍,每個接口對應(yīng)了一種類型的事件褪猛,供Reactor在相應(yīng)的事件發(fā)生時調(diào)用,執(zhí)行相應(yīng)的事件處理羹饰。通常它會綁定一個有效的句柄伊滋。
對應(yīng)到libevent中碳却,就是event結(jié)構(gòu)體。
下面是兩種典型的Event Handler類聲明方式笑旺,二者互有優(yōu)缺點(diǎn)昼浦。
class Event_Handler
{
public:
virtual void handle_read() = 0;
virtual void handle_write() = 0;
virtual void handle_timeout() = 0;
virtual void handle_close() = 0;
virtual HANDLE get_handle() = 0;
// ...
};
class Event_Handler
{
public:
// events maybe read/write/timeout/close .etc
virtual void handle_events(int events) = 0;
virtual HANDLE get_handle() = 0;
// ...
};