中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

服務(wù)專業(yè)建設(shè)武漢官網(wǎng)優(yōu)化公司

服務(wù)專業(yè)建設(shè),武漢官網(wǎng)優(yōu)化公司,安徽奶茶加盟網(wǎng)站建設(shè),有祥云網(wǎng)站文章目錄 一、Poll(一)定義(二)實現(xiàn)原理(三)優(yōu)點(四)缺點 二、I/O多路轉(zhuǎn)接之epoll(一)從網(wǎng)卡接收數(shù)據(jù)說起(二)如何知道接收了數(shù)據(jù)&…

在這里插入圖片描述

文章目錄

  • 一、Poll
    • (一)定義
    • (二)實現(xiàn)原理
    • (三)優(yōu)點
    • (四)缺點
  • 二、I/O多路轉(zhuǎn)接之epoll
    • (一)從網(wǎng)卡接收數(shù)據(jù)說起
    • (二)如何知道接收了數(shù)據(jù)?
    • (三)進(jìn)程阻塞為什么不占用cpu資源?
      • 1.工作隊列
      • 2.等待隊列
      • 3.喚醒進(jìn)程
    • (四)內(nèi)核接收網(wǎng)絡(luò)數(shù)據(jù)全過程
    • (五)同時監(jiān)視多個socket的簡單方法
      • 1.select的流程
  • 三、epoll詳解
    • (一)epoll的設(shè)計思路
      • 1.措施一:功能分離
      • 2.措施二:就緒列表
    • (二)epoll的原理和流程
      • 1.創(chuàng)建epoll對象
      • 2.維護(hù)監(jiān)視列表
      • 3.接收數(shù)據(jù)
      • 4.阻塞和喚醒進(jìn)程
    • (三)epoll的實現(xiàn)細(xì)節(jié)
      • 1.就緒列表的數(shù)據(jù)結(jié)構(gòu)
      • 2.索引結(jié)構(gòu)
      • 3.使用過程就是三部曲:
  • 四、epoll的不同工作模式
    • (一)水平觸發(fā)Level Triggered 工作模式
    • (二)邊緣觸發(fā)Edge Triggered工作模式
    • (三)對比LT和ET
  • 五、Reactor
    • (一)定義
    • (二)組成部分

部分內(nèi)容轉(zhuǎn)載自:

一、Poll

(一)定義

poll是Linux的事件輪詢機(jī)制函數(shù),每個進(jìn)程都可以管理一個pollfd隊列,由poll函數(shù)進(jìn)行事件注冊和查詢。

struct pollfd
{int fd; short events;short revents; 
}#include <poll.h>
int poll(struct pollfd* fds, nfds_t nfds, int timeout);

在這里插入圖片描述
在這里插入圖片描述

(二)實現(xiàn)原理

內(nèi)核將用戶的fds結(jié)構(gòu)體數(shù)組拷貝到內(nèi)核中。當(dāng)有事件發(fā)生時,再將所有事件都返回到fds結(jié)構(gòu)體數(shù)組中,poll只返回已就緒事件的個數(shù),所以用戶要操作就緒事件就要用輪詢的方法。

(三)優(yōu)點

不同與select使用三個位圖來表示三個fdset的方式,poll使用一個pollfd的指針實現(xiàn).
pollfd結(jié)構(gòu)包含了要監(jiān)視的event和發(fā)生的event,不再使用select“參數(shù)-值”傳遞的方式. 接口使用比
select更方便!

(四)缺點

poll中監(jiān)聽的文件描述符數(shù)目增多時:
和select函數(shù)一樣,poll返回后,需要輪詢pollfd來獲取就緒的描述符.

  • 每次調(diào)用poll都需要把大量的pollfd結(jié)構(gòu)從用戶態(tài)拷貝到內(nèi)核中.
  • 同時連接的大量客戶端在一時刻可能只有很少的處于就緒狀態(tài), 因此隨著監(jiān)視的描述符數(shù)量的增長, 其效率也會線性下降。

二、I/O多路轉(zhuǎn)接之epoll

(一)從網(wǎng)卡接收數(shù)據(jù)說起

下圖是一個典型的計算機(jī)結(jié)構(gòu)圖,計算機(jī)由CPU、存儲器(內(nèi)存)、網(wǎng)絡(luò)接口等部件組成。了解epoll本質(zhì)的第一步,要從硬件的角度看計算機(jī)怎樣接收網(wǎng)絡(luò)數(shù)據(jù)。

下圖展示了網(wǎng)卡接收數(shù)據(jù)的過程。在①階段,網(wǎng)卡收到網(wǎng)線傳來的數(shù)據(jù);經(jīng)過②階段的硬件電路的傳輸;最終將數(shù)據(jù)寫入到內(nèi)存中的某個地址上(③階段)。這個過程涉及到DMA傳輸、IO通路選擇等硬件有關(guān)的知識,但我們只需知道:網(wǎng)卡會把接收到的數(shù)據(jù)寫入內(nèi)存。
在這里插入圖片描述
網(wǎng)卡接收數(shù)據(jù)的過程:

通過硬件傳輸,網(wǎng)卡接收的數(shù)據(jù)存放到內(nèi)存中。操作系統(tǒng)就可以去讀取它們。

(二)如何知道接收了數(shù)據(jù)?

了解epoll本質(zhì)的第二步,要從CPU的角度來看數(shù)據(jù)接收。要理解這個問題,要先了解一個概念——中斷。
計算機(jī)執(zhí)行程序時,會有優(yōu)先級的需求。比如,當(dāng)計算機(jī)收到斷電信號時(電容可以保存少許電量,供CPU運行很短的一小段時間),它應(yīng)立即去保存數(shù)據(jù),保存數(shù)據(jù)的程序具有較高的優(yōu)先級。

一般而言,由硬件產(chǎn)生的信號需要cpu立馬做出回應(yīng)(不然數(shù)據(jù)可能就丟失),所以它的優(yōu)先級很高。cpu理應(yīng)中斷掉正在執(zhí)行的程序,去做出響應(yīng);當(dāng)cpu完成對硬件的響應(yīng)后,再重新執(zhí)行用戶程序。中斷的過程如下圖,和函數(shù)調(diào)用差不多。只不過函數(shù)調(diào)用是事先定好位置,而中斷的位置由“信號”決定。
在這里插入圖片描述

  • 中斷程序調(diào)用

以鍵盤為例,當(dāng)用戶按下鍵盤某個按鍵時,鍵盤會給cpu的中斷引腳發(fā)出一個高電平。cpu能夠捕獲這個信號,然后執(zhí)行鍵盤中斷程序。下圖展示了各種硬件通過中斷與cpu交互。
在這里插入圖片描述

現(xiàn)在可以回答本節(jié)提出的問題了:當(dāng)網(wǎng)卡把數(shù)據(jù)寫入到內(nèi)存后,網(wǎng)卡向cpu發(fā)出一個中斷信號,操作系統(tǒng)便能得知有新數(shù)據(jù)到來,再通過網(wǎng)卡中斷程序去處理數(shù)據(jù)!

(三)進(jìn)程阻塞為什么不占用cpu資源?

了解epoll本質(zhì)的第三步,要從操作系統(tǒng)進(jìn)程調(diào)度的角度來看數(shù)據(jù)接收。阻塞是進(jìn)程調(diào)度的關(guān)鍵一環(huán),指的是進(jìn)程在等待某事件(如接收到網(wǎng)絡(luò)數(shù)據(jù))發(fā)生之前的等待狀態(tài),recv、select和epoll都是阻塞方法。了解“進(jìn)程阻塞為什么不占用cpu資源?”,也就能夠了解這一步。
那么阻塞的原理是什么?

為簡單起見,我們從普通的recv接收開始分析,先看看下面代碼:

//創(chuàng)建socket
accept =+ 獲取!!!
多路轉(zhuǎn)接io!!
select 只負(fù)責(zé)等!!
accept 負(fù)責(zé)獲取!!int s = socket(AF_INET, SOCK_STREAM, 0);   //綁定bind(s, ...)//監(jiān)聽listen(s, ...)//接受客戶端連接int c = accept(s, ...)//接收客戶端數(shù)據(jù)recv(c, ...);//將數(shù)據(jù)打印出來printf(...)

這是一段最基礎(chǔ)的網(wǎng)絡(luò)編程代碼,先新建socket對象,依次調(diào)用bind、listen、accept,最后調(diào)用recv接收數(shù)據(jù)。recv是個阻塞方法,當(dāng)程序運行到recv時,它會一直等待,直到接收到數(shù)據(jù)才往下執(zhí)行。

1.工作隊列

操作系統(tǒng)為了支持多任務(wù),實現(xiàn)了進(jìn)程調(diào)度的功能,會把進(jìn)程分為“運行”和“等待”等幾種狀態(tài)。運行狀態(tài)是進(jìn)程獲得cpu使用權(quán),正在執(zhí)行代碼的狀態(tài);等待狀態(tài)是阻塞狀態(tài),比如上述程序運行到recv時,程序會從運行狀態(tài)變?yōu)榈却隣顟B(tài),接收到數(shù)據(jù)后又變回運行狀態(tài)。操作系統(tǒng)會分時執(zhí)行各個運行狀態(tài)的進(jìn)程,由于速度很快,看上去就像是同時執(zhí)行多個任務(wù)。
下圖中的計算機(jī)中運行著A、B、C三個進(jìn)程,其中進(jìn)程A執(zhí)行著上述基礎(chǔ)網(wǎng)絡(luò)程序,一開始,這3個進(jìn)程都被操作系統(tǒng)的工作隊列所引用,處于運行狀態(tài),會分時執(zhí)行。
在這里插入圖片描述
工作隊列中有A、B和C三個進(jìn)程

2.等待隊列

當(dāng)進(jìn)程A執(zhí)行到創(chuàng)建socket的語句時,操作系統(tǒng)會創(chuàng)建一個由文件系統(tǒng)管理的socket對象(如下圖)。這個socket對象包含了發(fā)送緩沖區(qū)、接收緩沖區(qū)、等待隊列等成員。等待隊列是個非常重要的結(jié)構(gòu),它指向所有需要等待該socket事件的進(jìn)程。
在這里插入圖片描述

  • 創(chuàng)建socket
    當(dāng)程序執(zhí)行到recv時,操作系統(tǒng)會將進(jìn)程A從工作隊列移動到該socket的等待隊列中(如下圖)。由于工作隊列只剩下了進(jìn)程B和C,依據(jù)進(jìn)程調(diào)度,cpu會輪流執(zhí)行這兩個進(jìn)程的程序,不會執(zhí)行進(jìn)程A的程序。所以進(jìn)程A被阻塞,不會往下執(zhí)行代碼,也不會占用cpu資源。
    在這里插入圖片描述
  • socket的等待隊列
    ps:操作系統(tǒng)添加等待隊列只是添加了對這個“等待中”進(jìn)程的引用,以便在接收到數(shù)據(jù)時獲取進(jìn)程對象、將其喚醒,而非直接將進(jìn)程管理納入自己之下。上圖為了方便說明,直接將進(jìn)程掛到等待隊列之下。

3.喚醒進(jìn)程

當(dāng)socket接收到數(shù)據(jù)后,操作系統(tǒng)將該socket等待隊列上的進(jìn)程重新放回到工作隊列,該進(jìn)程變成運行狀態(tài),繼續(xù)執(zhí)行代碼。也由于socket的接收緩沖區(qū)已經(jīng)有了數(shù)據(jù),recv可以返回接收到的數(shù)據(jù)。

(四)內(nèi)核接收網(wǎng)絡(luò)數(shù)據(jù)全過程

這一步,貫穿網(wǎng)卡、中斷、進(jìn)程調(diào)度的知識,敘述阻塞recv下,內(nèi)核接收數(shù)據(jù)全過程。
如下圖所示,進(jìn)程在recv阻塞期間,計算機(jī)收到了對端傳送的數(shù)據(jù)(步驟①)。數(shù)據(jù)經(jīng)由網(wǎng)卡傳送到內(nèi)存(步驟②),然后網(wǎng)卡通過中斷信號通知cpu有數(shù)據(jù)到達(dá),cpu執(zhí)行中斷程序(步驟③)。此處的中斷程序主要有兩項功能,先將網(wǎng)絡(luò)數(shù)據(jù)寫入到對應(yīng)socket的接收緩沖區(qū)里面(步驟④),再喚醒進(jìn)程A(步驟⑤),重新將進(jìn)程A放入工作隊列中。
在這里插入圖片描述
內(nèi)核接收數(shù)據(jù)全過程

喚醒進(jìn)程的過程如下圖所示。
在這里插入圖片描述
喚醒進(jìn)程:
以上是內(nèi)核接收數(shù)據(jù)全過程

這里留有兩個思考題,大家先想一想。

其一,操作系統(tǒng)如何知道網(wǎng)絡(luò)數(shù)據(jù)對應(yīng)于哪個socket?

其二,如何同時監(jiān)視多個socket的數(shù)據(jù)

第一個問題:因為一個socket對應(yīng)著一個端口號,而網(wǎng)絡(luò)數(shù)據(jù)包中包含了ip和端口的信息,內(nèi)核可以通過端口號找到對應(yīng)的socket。當(dāng)然,為了提高處理速度,操作系統(tǒng)會維護(hù)端口號到socket的索引結(jié)構(gòu),以快速讀取。
第二個問題是多路復(fù)用的重中之重,是本文后半部分的重點!

(五)同時監(jiān)視多個socket的簡單方法

服務(wù)端需要管理多個客戶端連接,而recv只能監(jiān)視單個socket,這種矛盾下,人們開始尋找監(jiān)視多個socket的方法。epoll的要義是高效的監(jiān)視多個socket。從歷史發(fā)展角度看,必然先出現(xiàn)一種不太高效的方法,人們再加以改進(jìn)。只有先理解了不太高效的方法,才能夠理解epoll的本質(zhì)。

假如能夠預(yù)先傳入一個socket列表,如果列表中的socket都沒有數(shù)據(jù),掛起進(jìn)程,直到有一個socket收到數(shù)據(jù),喚醒進(jìn)程。這種方法很直接,也是select的設(shè)計思想。

為方便理解,我們先復(fù)習(xí)select的用法。在如下的代碼中,先準(zhǔn)備一個數(shù)組(下面代碼中的fds),讓fds存放著所有需要監(jiān)視的socket。然后調(diào)用select,如果fds中的所有socket都沒有數(shù)據(jù),select會阻塞,直到有一個socket接收到數(shù)據(jù),select返回,喚醒進(jìn)程。用戶可以遍歷fds,通過FD_ISSET判斷具體哪個socket收到數(shù)據(jù),然后做出處理。

int s = socket(AF_INET, SOCK_STREAM, 0);  
bind(s, ...)
listen(s, ...)int fds[] =  存放需要監(jiān)聽的socketwhile(1){int n = select(..., fds, ...)for(int i=0; i < fds.count; i++){if(FD_ISSET(fds[i], ...)){//fds[i]的數(shù)據(jù)處理}}
}

1.select的流程

select的實現(xiàn)思路很直接。假如程序同時監(jiān)視如下圖的sock1、sock2和sock3三個socket,那么在調(diào)用select之后,操作系統(tǒng)把進(jìn)程A分別加入這三個socket的等待隊列中。
在這里插入圖片描述
操作系統(tǒng)把進(jìn)程A分別加入這三個socket的等待隊列中

當(dāng)任何一個socket收到數(shù)據(jù)后,中斷程序?qū)酒疬M(jìn)程。下圖展示了sock2接收到了數(shù)據(jù)的處理流程。
在這里插入圖片描述
sock2接收到了數(shù)據(jù),中斷程序喚起進(jìn)程A

所謂喚起進(jìn)程,就是將進(jìn)程從所有的等待隊列中移除,加入到工作隊列里面。如下圖所示。
在這里插入圖片描述
將進(jìn)程A從所有等待隊列中移除,再加入到工作隊列里面

經(jīng)由這些步驟,當(dāng)進(jìn)程A被喚醒后,它知道至少有一個socket接收了數(shù)據(jù)。程序只需遍歷一遍socket列表,就可以得到就緒的socket。

這種簡單方式行之有效,在幾乎所有操作系統(tǒng)都有對應(yīng)的實現(xiàn)。
但是簡單的方法往往有缺點,主要是:
其一,每次調(diào)用select都需要將進(jìn)程加入到所有監(jiān)視socket的等待隊列,每次喚醒都需要從每個隊列中移除。這里涉及了兩次遍歷,而且每次都要將整個fds列表傳遞給內(nèi)核,有一定的開銷。正是因為遍歷操作開銷大,出于效率的考量,才會規(guī)定select的最大監(jiān)視數(shù)量,默認(rèn)只能監(jiān)視1024個socket。
其二,進(jìn)程被喚醒后,程序并不知道哪些socket收到數(shù)據(jù),還需要遍歷一次。

三、epoll詳解

(一)epoll的設(shè)計思路

epoll是在select出現(xiàn)N多年后才被發(fā)明的,是select和poll的增強版本。epoll通過以下一些措施來改進(jìn)效率。
linux的最后一節(jié)學(xué)習(xí)!

1.措施一:功能分離

select低效的原因之一是將“維護(hù)等待隊列”和“阻塞進(jìn)程”兩個步驟合二為一。如下圖所示,每次調(diào)用select都需要這兩步操作,然而大多數(shù)應(yīng)用場景中,需要監(jiān)視的socket相對固定,并不需要每次都修改。epoll將這兩個操作分開,先用epoll_ctl維護(hù)等待隊列,再調(diào)用epoll_wait阻塞進(jìn)程。顯而易見的,效率就能得到提升
在這里插入圖片描述
相比select,epoll拆分了功能

為方便理解后續(xù)的內(nèi)容,我們先復(fù)習(xí)下epoll的用法。如下的代碼中,先用epoll_create創(chuàng)建一個epoll對象epfd,再通過epoll_ctl將需要監(jiān)視的socket添加到epfd中,最后調(diào)用epoll_wait等待數(shù)據(jù)

int s = socket(AF_INET, SOCK_STREAM, 0);   
bind(s, ...)
listen(s, ...)int epfd = epoll_create(...);
epoll_ctl(epfd, ...); //將所有需要監(jiān)聽的socket添加到epfd中while(1){int n = epoll_wait(...)for(接收到數(shù)據(jù)的socket){//處理}
}

功能分離,使得epoll有了優(yōu)化的可能。

2.措施二:就緒列表

select低效的另一個原因在于程序不知道哪些socket收到數(shù)據(jù),只能一個個遍歷。如果內(nèi)核維護(hù)一個“就緒列表”,引用收到數(shù)據(jù)的socket,就能避免遍歷。如下圖所示,計算機(jī)共有三個socket,收到數(shù)據(jù)的sock2和sock3被rdlist(就緒列表)所引用。當(dāng)進(jìn)程被喚醒后,只要獲取rdlist的內(nèi)容,就能夠知道哪些socket收到數(shù)據(jù)。
在這里插入圖片描述

(二)epoll的原理和流程

1.創(chuàng)建epoll對象

如下圖所示,當(dāng)某個進(jìn)程調(diào)用epoll_create方法時,內(nèi)核會創(chuàng)建一個eventpoll對象(也就是程序中epfd所代表的對象)。eventpoll對象也是文件系統(tǒng)中的一員,和socket一樣,它也會有等待隊列。

int epoll_create(int size); // 幫我們創(chuàng)建一個epoll模型

內(nèi)核創(chuàng)建eventpoll對象!
在這里插入圖片描述

創(chuàng)建一個代表該epoll的eventpoll對象是必須的,因為內(nèi)核要維護(hù)“就緒列表”等數(shù)據(jù),“就緒列表”可以作為eventpoll的成員。

2.維護(hù)監(jiān)視列表

創(chuàng)建epoll對象后,可以用epoll_ctl添加或刪除所要監(jiān)聽的socket。以添加socket為例,如下圖,如果通過epoll_ctl添加sock1、sock2和sock3的監(jiān)視,內(nèi)核會將eventpoll添加到這三個socket的等待隊列中。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll的事件注冊函數(shù).
它不同于select()是在監(jiān)聽事件時告訴內(nèi)核要監(jiān)聽什么類型的事件, 而是在這里先注冊要監(jiān)聽的事件類型. 
第一個參數(shù)是epoll_create()的返回值(epoll的句柄).
第二個參數(shù)表示動作,用三個宏來表示. 
第三個參數(shù)是需要監(jiān)聽的fd. 
第四個參數(shù)是告訴內(nèi)核需要監(jiān)聽什么事.
第二個參數(shù)的取值:
EPOLL_CTL_ADD :注冊新的fd到epfd中;
EPOLL_CTL_MOD :修改已經(jīng)注冊的fd的監(jiān)聽事件;
EPOLL_CTL_DEL :從epfd中刪除一個fd;struct epoll_event結(jié)構(gòu)如下:
struct epoll_event {__uint32_t events;      /* epoll event */epoll_data_t data;      /* User data variable */
};events可以是以下幾個宏的集合:
EPOLLIN : 表示對應(yīng)的文件描述符可以讀 (包括對端SOCKET正常關(guān)閉); 
EPOLLOUT : 表示對應(yīng)的文件描述符可以寫;
EPOLLPRI : 表示對應(yīng)的文件描述符有緊急的數(shù)據(jù)可讀 (這里應(yīng)該表示有帶外數(shù)據(jù)到來);
EPOLLERR : 表示對應(yīng)的文件描述符發(fā)生錯誤;
EPOLLHUP : 表示對應(yīng)的文件描述符被掛斷;
EPOLLET : 將EPOLL設(shè)為邊緣觸發(fā)(Edge Triggered)模式, 這是相對于水平觸發(fā)(Level Triggered)來說的.
EPOLLONESHOT:只監(jiān)聽一次事件, 當(dāng)監(jiān)聽完這次事件之后, 如果還需要繼續(xù)監(jiān)聽這個socket的話, 需要
再次把這個socket加入到EPOLL隊列里.

在這里插入圖片描述
添加所要監(jiān)聽的socket
當(dāng)socket收到數(shù)據(jù)后,中斷程序會操作eventpoll對象,而不是直接操作進(jìn)程。

3.接收數(shù)據(jù)

當(dāng)socket收到數(shù)據(jù)后,中斷程序會給eventpoll的“就緒列表”添加socket引用。如下圖展示的是sock2和sock3收到數(shù)據(jù)后,中斷程序讓rdlist引用這兩個socket。
在這里插入圖片描述
給就緒列表添加引用

eventpoll對象相當(dāng)于是socket和進(jìn)程之間的中介,socket的數(shù)據(jù)接收并不直接影響進(jìn)程,而是通過改變eventpoll的就緒列表來改變進(jìn)程狀態(tài)。
當(dāng)程序執(zhí)行到epoll_wait時,如果rdlist已經(jīng)引用了socket,那么epoll_wait直接返回,如果rdlist為空,阻塞進(jìn)程。

4.阻塞和喚醒進(jìn)程

假設(shè)計算機(jī)中正在運行進(jìn)程A和進(jìn)程B,在某時刻進(jìn)程A運行到了epoll_wait語句。如下圖所示,內(nèi)核會將進(jìn)程A放入eventpoll的等待隊列中,阻塞進(jìn)程。
在這里插入圖片描述
epoll_wait阻塞進(jìn)程:

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
收集在epoll監(jiān)控的事件中已經(jīng)發(fā)送的事件!
參數(shù)events是分配好的epoll_event結(jié)構(gòu)體數(shù)組. 
epoll將會把發(fā)生的事件賦值到events數(shù)組中 (events不可以是空指針,內(nèi)核只負(fù)責(zé)把數(shù)據(jù)復(fù)制到這個
events數(shù)組中,不會去幫助我們在用戶態(tài)中分配內(nèi)存). 
maxevents告之內(nèi)核這個events有多大,這個 maxevents的值不能大于創(chuàng)建epoll_create()時的size. 
參數(shù)timeout是超時時間 (毫秒,0會立即返回,-1是永久阻塞). 
如果函數(shù)調(diào)用成功,返回對應(yīng)I/O上已準(zhǔn)備好的文件描述符數(shù)目,如返回0表示已超時, 返回小于0表示函
數(shù)失敗.

當(dāng)socket接收到數(shù)據(jù),中斷程序一方面修改rdlist,另一方面喚醒eventpoll等待隊列中的進(jìn)程,進(jìn)程A再次進(jìn)入運行狀態(tài)(如下圖)。也因為rdlist的存在,進(jìn)程A可以知道哪些socket發(fā)生了變化。

在這里插入圖片描述

(三)epoll的實現(xiàn)細(xì)節(jié)

eventpoll的數(shù)據(jù)結(jié)構(gòu)是什么樣子?
再留兩個問題,就緒隊列應(yīng)該應(yīng)使用什么數(shù)據(jù)結(jié)構(gòu)?eventpoll應(yīng)使用什么數(shù)據(jù)結(jié)構(gòu)來管理通過epoll_ctl添加或刪除的socket?
如下圖所示,eventpoll包含了lock、mtx、wq(等待隊列)、rdlist等成員。rdlist和rbr是我們所關(guān)心的。

在這里插入圖片描述
當(dāng)某一進(jìn)程調(diào)用epoll_create方法時,Linux內(nèi)核會創(chuàng)建一個eventpoll結(jié)構(gòu)體,這個結(jié)構(gòu)體中有兩個成
員與epoll的使用方式密切相關(guān).

struct eventpoll{ .... /*紅黑樹的根節(jié)點,這顆樹中存儲著所有添加到epoll中的需要監(jiān)控的事件*/ struct rb_root rbr; /*雙鏈表中則存放著將要通過epoll_wait返回給用戶的滿足條件的事件*/ struct list_head rdlist; .... 
};
  • 每一個epoll對象都有一個獨立的eventpoll結(jié)構(gòu)體,用于存放通過epoll_ctl方法向epoll對象中添加進(jìn)來
    的事件.
  • 這些事件都會掛載在紅黑樹中,如此,重復(fù)添加的事件就可以通過紅黑樹而高效的識別出來(紅黑樹的插
    入時間效率是lgn,其中n為樹的高度).
  • 而所有添加到epoll中的事件都會與設(shè)備(網(wǎng)卡)驅(qū)動程序建立回調(diào)關(guān)系,也就是說,當(dāng)響應(yīng)的事件發(fā)生時
    會調(diào)用這個回調(diào)方法.
  • 這個回調(diào)方法在內(nèi)核中叫ep_poll_callback,它會將發(fā)生的事件添加到rdlist雙鏈表中.
  • 在epoll中,對于每一個事件,都會建立一個epitem結(jié)構(gòu)體.
struct epitem{ struct rb_node rbn;//紅黑樹節(jié)點 struct list_head rdllink;//雙向鏈表節(jié)點 struct epoll_filefd ffd; //事件句柄信息 struct eventpoll *ep; //指向其所屬的eventpoll對象 struct epoll_event event; //期待發(fā)生的事件類型 
}

當(dāng)調(diào)用epoll_wait檢查是否有事件發(fā)生時,只需要檢查eventpoll對象中的rdlist雙鏈表中是否有epitem
元素即可. 如果rdlist不為空,則把發(fā)生的事件復(fù)制到用戶態(tài),同時將事件數(shù)量返回給用戶. 這個操作的時間復(fù)雜度是O(1).

1.就緒列表的數(shù)據(jù)結(jié)構(gòu)

就緒列表引用著就緒的socket,所以它應(yīng)能夠快速的插入數(shù)據(jù)。

程序可能隨時調(diào)用epoll_ctl添加監(jiān)視socket,也可能隨時刪除。當(dāng)刪除時,若該socket已經(jīng)存放在就緒列表中,它也應(yīng)該被移除。

所以就緒列表應(yīng)是一種能夠快速插入和刪除的數(shù)據(jù)結(jié)構(gòu)。雙向鏈表就是這樣一種數(shù)據(jù)結(jié)構(gòu),epoll使用雙向鏈表來實現(xiàn)就緒隊列(對應(yīng)上圖的rdllist)。

2.索引結(jié)構(gòu)

既然epoll將“維護(hù)監(jiān)視隊列”和“進(jìn)程阻塞”分離,也意味著需要有個數(shù)據(jù)結(jié)構(gòu)來保存監(jiān)視的socket。至少要方便的添加和移除,還要便于搜索,以避免重復(fù)添加。紅黑樹是一種自平衡二叉查找樹,搜索、插入和刪除時間復(fù)雜度都是O(log(N)),效率較好。epoll使用了紅黑樹作為索引結(jié)構(gòu)(對應(yīng)上圖的rbr)。

3.使用過程就是三部曲:

  1. 調(diào)用epoll_create創(chuàng)建一個epoll句柄;
  2. 調(diào)用epoll_ctl, 將要監(jiān)控的文件描述符進(jìn)行注冊;
  3. 調(diào)用epoll_wait, 等待文件描述符就緒;

四、epoll的不同工作模式

例子:你正在吃雞, 眼看進(jìn)入了決賽圈, 你媽飯做好了, 喊你吃飯的時候有兩種方式:

  1. 如果你媽喊你一次, 你沒動, 那么你媽會繼續(xù)喊你第二次, 第三次…(親媽, 水平觸發(fā))
  2. 如果你媽喊你一次, 你沒動, 你媽就不管你了(后媽, 邊緣觸發(fā))
    取快遞:張三,喊你無數(shù)次(水平)lt (Level Triggered )
    李四:喊你一次(邊緣)et (Edge Triggered工)

(一)水平觸發(fā)Level Triggered 工作模式

epoll默認(rèn)狀態(tài)下就是LT工作模式.

  • 當(dāng)epoll檢測到socket上事件就緒的時候, 可以不立刻進(jìn)行處理. 或者只處理一部分.
  • 如上面的例子, 由于只讀了1K數(shù)據(jù), 緩沖區(qū)中還剩1K數(shù)據(jù), 在第二次調(diào)用 epoll_wait 時, epoll_wait
    仍然會立刻返回并通知socket讀事件就緒.
  • 直到緩沖區(qū)上所有的數(shù)據(jù)都被處理完, epoll_wait 才不會立刻返回.
  • 支持阻塞讀寫和非阻塞讀寫

(二)邊緣觸發(fā)Edge Triggered工作模式

如果我們在第1步將socket添加到epoll描述符的時候使用了EPOLLET標(biāo)志, epoll進(jìn)入ET工作模式.

  • 當(dāng)epoll檢測到socket上事件就緒時, 必須立刻處理.
  • 如上面的例子, 雖然只讀了1K的數(shù)據(jù), 緩沖區(qū)還剩1K的數(shù)據(jù), 在第二次調(diào)用 epoll_wait 的時候,
    epoll_wait 不會再返回了.
  • 也就是說, ET模式下, 文件描述符上的事件就緒后, 只有一次處理機(jī)會.
  • ET的性能比LT性能更高( epoll_wait 返回的次數(shù)少了很多). Nginx默認(rèn)采用ET模式使用epoll.
  • 只支持非阻塞的讀寫

select和poll其實也是工作在LT模式下. epoll既可以支持LT, 也可以支持ET。

(三)對比LT和ET

  • LT是 epoll 的默認(rèn)行為. 使用 ET 能夠減少 epoll 觸發(fā)的次數(shù). 但是代價就是強逼著程序猿一次響應(yīng)就緒過程中就把所有的數(shù)據(jù)都處理完.
    相當(dāng)于一個文件描述符就緒之后, 不會反復(fù)被提示就緒, 看起來就比 LT 更高效一些. 但是在 LT 情況下如果也能做到每次就緒的文件描述符都立刻處理, 不讓這個就緒被重復(fù)提示的話, 其實性能也是一樣的.
  • 另一方面, ET 的代碼復(fù)雜程度更高了.

五、Reactor

(一)定義

Reactor 翻譯過來的意思是「反應(yīng)堆」,可能大家會聯(lián)想到物理學(xué)里的核反應(yīng)堆,實際上并不是的這個意思。
這里反應(yīng)指的是「對事件反應(yīng)」,也就是來了一個事件,Reactor 就有相對應(yīng)的反應(yīng)/響應(yīng)。
在這里插入圖片描述

(二)組成部分

Reactor 模式主要由 Reactor 和處理資源池這兩個核心部分組成,它倆負(fù)責(zé)的事情如下:
Reactor 負(fù)責(zé)監(jiān)聽和分發(fā)事件,事件類型包含連接事件、讀寫事件;
處理資源池負(fù)責(zé)處理事件,如 read -> 業(yè)務(wù)邏輯 -> send;

2023.10.5.linux-end!
善始善終!

http://www.risenshineclean.com/news/23014.html

相關(guān)文章:

  • 做網(wǎng)站費用多少錢域名解析ip地址
  • 小熊源碼網(wǎng)新網(wǎng)站百度seo如何做
  • 建設(shè)招標(biāo)網(wǎng)網(wǎng)站網(wǎng)站關(guān)鍵詞優(yōu)化網(wǎng)站推廣
  • 自己做網(wǎng)站 搜索功能開發(fā)杭州網(wǎng)站seo優(yōu)化
  • 滄州手機(jī)建站哪家好濟(jì)南seo外包服務(wù)
  • dw做網(wǎng)站怎么設(shè)置頁面音樂網(wǎng)站大全軟件下載
  • 公司主頁怎么填寫seo軟件哪個好
  • 出國勞務(wù)信息網(wǎng)seo優(yōu)化網(wǎng)站源碼
  • 做公司網(wǎng)站需要服務(wù)器嗎上海關(guān)鍵詞排名提升
  • 一學(xué)一做短視頻網(wǎng)站杭州市優(yōu)化服務(wù)
  • 重慶網(wǎng)站空間鍵詞排名搜索引擎優(yōu)化的定義
  • 廣州各區(qū)優(yōu)化疫情防控措施seo引擎優(yōu)化公司
  • 做任務(wù)的獎金網(wǎng)站國際實時新聞
  • 國務(wù)院建設(shè)部網(wǎng)站seo數(shù)據(jù)是什么意思
  • 什么是網(wǎng)站名稱文件夾寵物美容師寵物美容培訓(xùn)學(xué)校
  • 上海專業(yè)網(wǎng)站建設(shè)機(jī)構(gòu)線上營銷平臺有哪些
  • 哪家公司建設(shè)網(wǎng)站嘉興關(guān)鍵詞優(yōu)化報價
  • 網(wǎng)站建設(shè)鼠標(biāo)移動變顏色百度seo
  • 做網(wǎng)站框架搭建的人優(yōu)化方法
  • 沒有服務(wù)器怎么做網(wǎng)站seo排名賺能賺錢嗎
  • wamp做的網(wǎng)站外網(wǎng)怎么訪問長春seo顧問
  • 鄭州做旅游網(wǎng)站品牌廣告文案
  • 濟(jì)南做網(wǎng)站哪家好企業(yè)網(wǎng)站注冊域名的步驟
  • 織夢dede門戶資訊新聞網(wǎng)站源碼濟(jì)南做網(wǎng)站公司
  • 網(wǎng)站建設(shè)能在家工作室廣州seo服務(wù)
  • 有沒有專門做衣服的網(wǎng)站360推廣開戶
  • 網(wǎng)站策劃與運營課程認(rèn)知如何建網(wǎng)站詳細(xì)步驟
  • 廣告設(shè)計樣板圖網(wǎng)站優(yōu)化外包推薦
  • 0基礎(chǔ)做網(wǎng)站工具網(wǎng)站建設(shè)的意義和目的
  • wordpress做seo好做seo搜索引擎優(yōu)化步驟