網路程式設計 反應堆reactor框架設計

2022-10-09 19:45:13 字數 4918 閱讀 1034

tcp 高效能網路框架需要滿足的需求有以下三點:

1)採用 reactor 模型,可以靈活使用 poll/epoll 作為事件分發實現。

2)必須支援多執行緒,從而可以支援單執行緒單 reactor 模式,也可以支援多執行緒主 - 從 reactor 模式。可以將套接字上的 i/o 事件分離到多個執行緒上。

3)封裝讀寫操作到 buffer 物件中。

按照這三個需求,正好可以把整體設計思路分成三塊來講解,分別包括反應堆模式設計、i/o 模型和多執行緒模型設計、資料讀寫封裝和 buffer。

反應堆模式設計

反應堆模式主要是設計乙個基於事件分發**的反應堆框架。這個框架裡面的主要物件包括:

i/o 模型和多執行緒模型設計

i/o 執行緒和多執行緒模型,主要解決event_loop 的執行緒執行問題,以及事件分發和**的執行緒執行問題

buffer 和資料讀寫

tcp_connection 是大部分應用程式和我們的高效能框架直接打交道的資料結構。我們不想把最下層的 channel 物件暴露給應用程式,因為抽象的 channel 物件不僅僅可以表示 tcp_connection,前面提到的監聽套接字也是乙個 channel 物件,後面提到的喚醒 socketpair 也是乙個 channel 物件。所以,我們設計了 tcp_connection 這個物件,希望可以提供給使用者比較清晰的程式設計入口。

概述以 event_loop 為核心的反應堆模式設計,這裡有一張 event_loop 的執行詳圖:

當 event_loop_run 完成之後,執行緒進入迴圈,首先執行 dispatch 事件分發,一旦有事件發生,就會呼叫 channel_event_activate 函式,在這個函式中完成事件**函式 eventreadcallback 和 eventwritecallback 的呼叫,最後再進行 event_loop_handle_pending_channel,用來修改當前監聽的事件列表,完成這個部分之後,又進入了事件分發迴圈。

event_loop 分析

在這個資料結構中,最重要的莫過於 event_dispatcher 物件了,可以簡單地把 event_dispatcher 理解為 poll 或者 epoll,它可以讓我們的執行緒掛起,等待事件的發生

這裡有乙個小技巧,就是 event_dispatcher_data,它被定義為乙個 void * 型別,可以按照我們的需求,任意放置乙個我們需要的物件指標。這樣,針對不同的實現,例如 poll 或者 epoll,都可以根據需求,放置不同的資料物件。

event_loop 中還保留了幾個跟多執行緒有關的物件,如 owner_thread_id 是保留了每個 event loop 的執行緒 id,mutex 和 con 是用來進行執行緒同步的。

socketpair 是父執行緒用來通知子執行緒有新的事件需要處理。pending_head 和 pending_tail 是保留在子執行緒內的需要處理的新事件。

struct event_loop ;
event_loop 最主要的方法 event_loop_run 方法,event_loop 就是乙個無限 while 迴圈,不斷地在分發事件

/**

* * 1.引數驗證

* 2.呼叫dispatcher來進行事件分發,分發完**事件處理函式

*/int event_loop_run(struct event_loop *eventloop)

yolanda_msgx("event loop run, %s", eventloop->thread_name);

struct timeval timeval;

timeval.tv_sec = 1;

while (!eventloop->quit)

yolanda_msgx("event loop end, %s", eventloop->thread_name);

return 0;

}

**很明顯地反映了這一點,這裡我們在 event_loop 不退出的情況下,一直在迴圈,迴圈體中呼叫了 dispatcher 物件的 dispatch 方法來等待事件的發生。

event_dispacher 分析

為了實現不同的事件分發機制,這裡把 poll、epoll 等抽象成了乙個 event_dispatcher 結構。event_dispatcher 的具體實現有 poll_dispatcher 和 epoll_dispatcher 兩種

/** 抽象的event_dispatcher結構體,對應的實現如select,poll,epoll等i/o復用. */

struct event_dispatcher ;

channel 物件分析

channel 物件是用來和 event_dispather 進行互動的最主要的結構體,它抽象了事件分發。乙個 channel 對應乙個描述字,描述字上可以有 read 可讀事件,也可以有 write 可寫事件。channel 物件繫結了事件處理函式 event_read_callback 和 event_write_callback。

typedef int (*event_read_callback)(void *data);

typedef int (*event_write_callback)(void *data);

struct channel ;

channel_map 物件分析

event_dispatcher 在獲得活動事件列表之後,需要通過檔案描述字找到對應的 channel,從而** channel 上的事件處理函式 event_read_callback 和 event_write_callback,為此,設計了 channel_map 物件。

/**

* channel對映表, key為對應的socket描述字

*/struct channel_map ;

channel_map 物件是乙個陣列,陣列的下標即為描述字,陣列的元素為 channel 物件的位址。

比如描述字 3 對應的 channel,就可以這樣直接得到。

struct chanenl * channel = map->entries[3];
這樣,當 event_dispatcher 需要** channel 上的讀、寫函式時,呼叫 channel_event_activate 就可以,下面是 channel_event_activate 的實現,在找到了對應的 channel 物件之後,根據事件型別,**了讀函式或者寫函式。注意,這裡使用了event_readevent_write來抽象了 poll 和 epoll 的所有讀寫事件型別。

int channel_event_activate(struct event_loop *eventloop, int fd, int revents) 

if (revents & (event_write))

return 0;

}

增加、刪除、修改 channel event

那麼如何增加新的 channel event 事件呢?下面這幾個函式是用來增加、刪除和修改 channel event 事件的。

int event_loop_add_channel_event(struct event_loop *eventloop, int fd, struct channel *channel1);

int event_loop_remove_channel_event(struct event_loop *eventloop, int fd, struct channel *channel1);

int event_loop_update_channel_event(struct event_loop *eventloop, int fd, struct channel *channel1);

前面三個函式提供了入口能力,而真正的實現則落在這三個函式上:

int event_loop_handle_pending_add(struct event_loop *eventloop, int fd, struct channel *channel);

int event_loop_handle_pending_remove(struct event_loop *eventloop, int fd, struct channel *channel);

int event_loop_handle_pending_update(struct event_loop *eventloop, int fd, struct channel *channel);

看一下其中的乙個實現,event_loop_handle_pending_add 在當前 event_loop 的 channel_map 裡增加乙個新的 key-value 對,key 是檔案描述字,value 是 channel 物件的位址。之後呼叫 event_dispatcher 物件的 add 方法增加 channel event 事件。注意這個方法總在當前的 i/o 執行緒中執行。

// in the i/o thread

int event_loop_handle_pending_add(struct event_loop *eventloop, int fd, struct channel *channel)

//第一次建立,增加

if ((map)->entries[fd] == null)

return 0;

}

reactor 反應堆模型

1.reactor模型,本質上講管理網路io 使用下面這個結構用來管理我們的io struct ntyreactor 下面這段 比較核心 我們關心的事件與發生的事件發生時,才去呼叫 2.實現 include include include include include include includ...

網路程式設計 epoll反應堆簡單版

反應堆簡單版 include include include include include include include include include include define buf len 1024 define event size 1024 全域性epoll樹的根 int gepf...

反應堆模式

1 定義 反應堆模式是一種物件行為類的設計模式,對同步事件分揀和派發。它是處理併發i o比較常見的一種模式,用於同步i o。其中心思想是將所有要處理的i o事件註冊到乙個中心i o多路復用器上,同時主線程阻塞在多路復用器上 一旦有i o事件到來或者是準備就緒,多路復用器返回並將相應的i o事件分發到...