大話「事件處理模式」

我是一名來自帝都 985 高校的機械研究生

本號專注於分享工科專業學習考試攻略、程序員學習求職經驗、教師求職考試經驗等相關內容,同時還會兼顧生活向,歡迎大家的關注和轉發!

圖片

目錄

服務器編程基本框架

兩種高效的事件處理模式

    Reactor 模式

    Proactor 模式

    模擬 Proactor 模式

服務器編程基本框架

雖然服務器程序種類繁多,但其基本框架都一樣,不同之處在於邏輯處理。

brKa5d

I/O 處理單元是服務器管理客戶連接的模塊。它通常要完成以下工作:等待並接受新的客戶連接,接收客戶數據,將服務器響應數據返回給客戶端。但是數據的收發不一定在 I/O 處理單元中執行,也可能在邏輯單元中執行,具體在何處執行取決於事件處理模式。

一個邏輯單元通常是一個進程或線程。它分析並處理客戶數據,然後將結果傳遞給 I/O 處理單元或者直接發送給客戶端(具體使用哪種方式取決於事件處理模式)。服務器通常擁有多個邏輯單元,以實現對多個客戶任務的併發處理。

網絡存儲單元可以是數據庫、緩存和文件,但不是必須的。

請求隊列是各單元之間的通信方式的抽象。I/O 處理單元接收到客戶請求時,需要以某種方式通知一個邏輯單元來處理該請求。同樣,多個邏輯單元同時訪問一個存儲單元時,也需要採用某種機制來協調處理競態條件。請求隊列通常被實現爲池的一部分。

兩種高效的事件處理模式

服務器程序通常需要處理三類事件:I/O 事件、信號及定時事件。有兩種高效的事件處理模式:Reactor 和 Proactor,同步 I/O 模型通常用於實現 Reactor 模式,異步 I/O 模型通常用於實現 Proactor 模式。

Reactor 模式

要求主線程(I/O 處理單元)只負責監聽文件描述符上是否有事件發生,有的話就立即將該事件通知工作線程(邏輯單元),將 socket 可讀可寫事件放入請求隊列,交給工作線程處理。除此之外,主線程不做任何其他實質性的工作。讀寫數據,接受新的連接,以及處理客戶請求均在工作線程中完成。

使用同步 I/O(以 epoll_wait 爲例)實現的 Reactor 模式的工作流程是:

  1. 主線程往 epoll 內核事件表中註冊 socket 上的讀就緒事件。

  2. 主線程調用 epoll_wait 等待 socket 上有數據可讀。

  3. 當 socket 上有數據可讀時, epoll_wait 通知主線程。主線程則將 socket 可讀事件放入請求隊列。

  4. 睡眠在請求隊列上的某個工作線程被喚醒,它從 socket 讀取數據,並處理客戶請求,然後往 epoll 內核事件表中註冊該 socket 上的寫就緒事件。

  5. 當主線程調用 epoll_wait 等待 socket 可寫。

  6. 當 socket 可寫時,epoll_wait 通知主線程。主線程將 socket 可寫事件放入請求隊列。

  7. 睡眠在請求隊列上的某個工作線程被喚醒,它往 socket 上寫入服務器處理客戶請求的結果。

Reactor 模式的工作流程:

Proactor 模式

Proactor 模式將所有 I/O 操作都交給主線程和內核來處理(進行讀、寫),工作線程僅僅負責業務邏輯。使用異步 I/O 模型(以 aio_read 和 aio_write 爲例)實現的 Proactor 模式的工作流程是:

  1. 主線程調用 aio_read 函數向內核註冊 socket 上的讀完成事件,並告訴內核用戶讀緩衝區的位置,以及讀操作完成時如何通知應用程序(這裏以信號爲例)。

  2. 主線程繼續處理其他邏輯。

  3. 當 socket 上的數據被讀入用戶緩衝區後,內核將嚮應用程序發送一個信號,以通知應用程序數據已經可用。

  4. 應用程序預先定義好的信號處理函數選擇一個工作線程來處理客戶請求。工作線程處理完客戶請求後,調用 aio_write 函數向內核註冊 socket 上的寫完成事件,並告訴內核用戶寫緩衝區的位置,以及寫操作完成時如何通知應用程序。

  5. 主線程繼續處理其他邏輯。

  6. 當用戶緩衝區的數據被寫入 socket 之後,內核將嚮應用程序發送一個信號,以通知應用程序數據已經發送完畢。

  7. 應用程序預先定義好的信號處理函數選擇一個工作線程來做善後處理,比如決定是否關閉 socket。

Proactor 模式的工作流程:

模擬 Proactor 模式

使用同步 I/O 方式模擬出 Proactor 模式。原理是:主線程執行數據讀寫操作,讀寫完成之後,主線程向工作線程通知這一” 完成事件 “。那麼從工作線程的角度來看,它們就直接獲得了數據讀寫的結果,接下來要做的只是對讀寫的結果進行邏輯處理。

使用同步 I/O 模型(以 epoll_wait 爲例)模擬出的 Proactor 模式的工作流程如下:

  1. 主線程往 epoll 內核事件表中註冊 socket 上的讀就緒事件。

  2. 主線程調用 epoll_wait 等待 socket 上有數據可讀。

  3. 當 socket 上有數據可讀時,epoll_wait 通知主線程。主線程從 socket 循環讀取數據,直到沒有更多數據可讀,然後將讀取到的數據封裝成一個請求對象並插入請求隊列。

  4. 睡眠在請求隊列上的某個工作線程被喚醒,它獲得請求對象並處理客戶請求,然後往 epoll 內核事件表中註冊 socket 上的寫就緒事件。

  5. 主線程調用 epoll_wait 等待 socket 可寫。

  6. 當 socket 可寫時,epoll_wait 通知主線程。主線程往 socket 上寫入服務器處理客戶請求的結果。

同步 I/O 模擬 Proactor 模式的工作流程:

我是一名來自帝都 985 高校的機械研究生

本號專注於分享工科專業學習考試攻略、程序員學習求職經驗、教師求職考試經驗等相關內容,同時還會兼顧生活向,歡迎大家的關注和轉發!

卡卡成長匯聚 我是來自帝都 985 高校的機械研究生,本號專注於工科專業學習考試攻略、程序員學習求職經驗,教師求職考試經驗相關內容,同時還會兼顧生活向,歡迎大家的關注和轉發!

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/delshZiAMOQ-3ynmNR4FYQ