0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

epoll源碼分析

科技綠洲 ? 來源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-13 11:49 ? 次閱讀

Linux內(nèi)核提供了3個(gè)關(guān)鍵函數(shù)供用戶來操作epoll,分別是:

  • epoll_create(), 創(chuàng)建eventpoll對象
  • epoll_ctl(), 操作eventpoll對象
  • epoll_wait(), 從eventpoll對象中返回活躍的事件

操作系統(tǒng)內(nèi)部會用到一個(gè)名叫epoll_event_callback()的回調(diào)函數(shù)來調(diào)度epoll對象中的事件,這個(gè)函數(shù)非常重要,故本文將會對上述4個(gè)函數(shù)進(jìn)行源碼分析。

源碼來源

由于epoll的實(shí)現(xiàn)內(nèi)嵌在內(nèi)核中,直接查看內(nèi)核源碼的話會有一些無關(guān)代碼影響閱讀。為此在GitHub上寫的簡化版TCP/IP協(xié)議棧,里面實(shí)現(xiàn)了epoll邏輯。鏈接為:
https://github.com/wangbojing/NtyTcp

存放著以上4個(gè)關(guān)鍵函數(shù)的文件是[srcnty_epoll_rb.c],本文接下來通過分析該程序的代碼來探索epoll能支持高并發(fā)連接的秘密。

兩個(gè)核心數(shù)據(jù)結(jié)構(gòu)

(1)epitem

圖片

如圖所示,epitem是中包含了兩個(gè)主要的成員變量,分別是rbn和rdlink,前者是紅黑樹的節(jié)點(diǎn),而后者是雙鏈表的節(jié)點(diǎn),也就是說一個(gè)epitem對象即可作為紅黑樹中的一個(gè)節(jié)點(diǎn)又可作為雙鏈表中的一個(gè)節(jié)點(diǎn)。并且每個(gè)epitem中存放著一個(gè)event,對event的查詢也就轉(zhuǎn)換成了對epitem的查詢。

struct epitem {
	RB_ENTRY(epitem) rbn;
	/*  RB_ENTRY(epitem) rbn等價(jià)于
	struct {											
		struct type *rbe_left;		//指向左子樹
		struct type *rbe_right;		//指向右子樹
		struct type *rbe_parent;	//指向父節(jié)點(diǎn)
		int rbe_color;			    //該節(jié)點(diǎn)的顏色
	} rbn
	*/

	LIST_ENTRY(epitem) rdlink;
	/* LIST_ENTRY(epitem) rdlink等價(jià)于
	struct {									
		struct type *le_next;	//指向下個(gè)元素
		struct type **le_prev;	//前一個(gè)元素的地址
	}*/

	int rdy; //判斷該節(jié)點(diǎn)是否同時(shí)存在與紅黑樹和雙向鏈表中
	
	int sockfd; //socket句柄
	struct epoll_event event;  //存放用戶填充的事件
};

(2)eventpoll

圖片

如圖所示,eventpoll中包含了兩個(gè)主要的成員變量,分別是rbr和rdlist,前者指向紅黑樹的根節(jié)點(diǎn),后者指向雙鏈表的頭結(jié)點(diǎn)。即一個(gè)eventpoll對象對應(yīng)二個(gè)epitem的容器。對epitem的檢索,將發(fā)生在這兩個(gè)容器上(紅黑樹和雙鏈表)。

struct eventpoll {
	/*
	struct ep_rb_tree {
		struct epitem *rbh_root; 			
	}
	*/
	ep_rb_tree rbr;      //rbr指向紅黑樹的根節(jié)點(diǎn)
	
	int rbcnt; //紅黑樹中節(jié)點(diǎn)的數(shù)量(也就是添加了多少個(gè)TCP連接事件)
	
	LIST_HEAD( ,epitem) rdlist;    //rdlist指向雙向鏈表的頭節(jié)點(diǎn);
	/*	這個(gè)LIST_HEAD等價(jià)于 
		struct {
			struct epitem *lh_first;
		}rdlist;
	*/
	
	int rdnum; //雙向鏈表中節(jié)點(diǎn)的數(shù)量(也就是有多少個(gè)TCP連接來事件了)

	// ...略...
	
};

四個(gè)關(guān)鍵函數(shù)

(1) epoll_create()

//創(chuàng)建epoll對象,包含一顆空紅黑樹和一個(gè)空雙向鏈表
int epoll_create(int size) {
	//與很多內(nèi)核版本一樣,size參數(shù)沒有作用,只要保證大于0即可
	if (size <= 0) return -1;
	
	nty_tcp_manager *tcp = nty_get_tcp_manager(); //獲取tcp對象
	if (!tcp) return -1;
	
	struct _nty_socket *epsocket = nty_socket_allocate(NTY_TCP_SOCK_EPOLL);
	if (epsocket == NULL) {
		nty_trace_epoll("malloc failedn");
		return -1;
	}

	// 1° 開辟了一塊內(nèi)存用于填充eventpoll對象
	struct eventpoll *ep = (struct eventpoll*)calloc(1, sizeof(struct eventpoll));
	if (!ep) {
		nty_free_socket(epsocket- >id, 0);
		return -1;
	}

	ep- >rbcnt = 0;

	// 2° 讓紅黑樹根指向空
	RB_INIT(&ep- >rbr);       //等價(jià)于ep- >rbr.rbh_root = NULL;

	// 3° 讓雙向鏈表的頭指向空
	LIST_INIT(&ep- >rdlist);  //等價(jià)于ep- >rdlist.lh_first = NULL;

	// 4° 并發(fā)環(huán)境下進(jìn)行互斥
	// ...該部分代碼與主線邏輯無關(guān),可自行查看...

	//5° 保存epoll對象
	tcp- >ep = (void*)ep;
	epsocket- >ep = (void*)ep;

	return epsocket- >id;
}

對以上代碼的邏輯進(jìn)行梳理,可以總結(jié)為以下6步:

  1. 創(chuàng)建eventpoll對象
  2. 讓eventpoll中的rbr指向空
  3. 讓eventpoll中的rdlist指向空
  4. 在并發(fā)環(huán)境下進(jìn)行互斥
  5. 保存eventpoll對象
  6. 返回eventpoll對象的句柄(id)

(2)epoll_ctl()

該函數(shù)的邏輯其實(shí)很簡單,無非就是將用戶傳入的參數(shù)封裝為一個(gè)epitem對象,然后根據(jù)傳入的op是①EPOLL_CTL_ADD、②EPOLL_CTL_MOD還是③EPOLL_CTL_DEL,來決定是①將epitem對象插入紅黑樹中,②更新紅黑樹中的epitem對象,還是③移除紅黑樹中的epitem對象。

//往紅黑樹中加每個(gè)tcp連接以及相關(guān)的事件
int epoll_ctl(int epid, int op, int sockid, struct epoll_event *event) {

	nty_tcp_manager *tcp = nty_get_tcp_manager();
	if (!tcp) return -1;

	nty_trace_epoll(" epoll_ctl -- > 1111111:%d, sockid:%dn", epid, sockid);
	struct _nty_socket *epsocket = tcp- >fdtable- >sockfds[epid];

	if (epsocket- >socktype == NTY_TCP_SOCK_UNUSED) {
		errno = -EBADF;
		return -1;
	}

	if (epsocket- >socktype != NTY_TCP_SOCK_EPOLL) {
		errno = -EINVAL;
		return -1;
	}

	nty_trace_epoll(" epoll_ctl -- > eventpolln");

	struct eventpoll *ep = (struct eventpoll*)epsocket- >ep;
	if (!ep || (!event && op != EPOLL_CTL_DEL)) {
		errno = -EINVAL;
		return -1;
	}

	if (op == EPOLL_CTL_ADD) {
		//添加sockfd上關(guān)聯(lián)的事件
		pthread_mutex_lock(&ep- >mtx);

		struct epitem tmp;
		tmp.sockfd = sockid;
		struct epitem *epi = RB_FIND(_epoll_rb_socket, &ep- >rbr, &tmp); //先在紅黑樹上找,根據(jù)key來找,也就是這個(gè)sockid,找的速度會非???/span>
		if (epi) {
			//原來有這個(gè)節(jié)點(diǎn),不能再次插入
			nty_trace_epoll("rbtree is existn");
			pthread_mutex_unlock(&ep- >mtx);
			return -1;
		}

		//只有紅黑樹上沒有該節(jié)點(diǎn)【沒有用過EPOLL_CTL_ADD的tcp連接才能走到這里】;

		//(1)生成了一個(gè)epitem對象,這個(gè)結(jié)構(gòu)對象,其實(shí)就是紅黑的一個(gè)節(jié)點(diǎn);
		epi = (struct epitem*)calloc(1, sizeof(struct epitem));
		if (!epi) {
			pthread_mutex_unlock(&ep- >mtx);
			errno = -ENOMEM;
			return -1;
		}
		
		//(2)把socket(TCP連接)保存到節(jié)點(diǎn)中;
		epi- >sockfd = sockid;  //作為紅黑樹節(jié)點(diǎn)的key,保存在紅黑樹中

		//(3)我們要增加的事件也保存到節(jié)點(diǎn)中;
		memcpy(&epi- >event, event, sizeof(struct epoll_event));

		//(4)把這個(gè)節(jié)點(diǎn)插入到紅黑樹中去
		epi = RB_INSERT(_epoll_rb_socket, &ep- >rbr, epi); //實(shí)際上這個(gè)時(shí)候epi的rbn成員就會發(fā)揮作用,如果這個(gè)紅黑樹中有多個(gè)節(jié)點(diǎn),那么RB_INSERT就會epi- >rbi相應(yīng)的值:可以參考圖來理解
		assert(epi == NULL);
		ep- >rbcnt ++;
		
		pthread_mutex_unlock(&ep- >mtx);

	} else if (op == EPOLL_CTL_DEL) {
		pthread_mutex_lock(&ep- >mtx);

		struct epitem tmp;
		tmp.sockfd = sockid;
		
		struct epitem *epi = RB_FIND(_epoll_rb_socket, &ep- >rbr, &tmp);//先在紅黑樹上找,根據(jù)key來找,也就是這個(gè)sockid,找的速度會非???/span>
		if (!epi) {
			nty_trace_epoll("rbtree no existn");
			pthread_mutex_unlock(&ep- >mtx);
			return -1;
		}
		
		//只有在紅黑樹上找到該節(jié)點(diǎn)【用過EPOLL_CTL_ADD的tcp連接才能走到這里】;

		//從紅黑樹上把這個(gè)節(jié)點(diǎn)移除
		epi = RB_REMOVE(_epoll_rb_socket, &ep- >rbr, epi);
		if (!epi) {
			nty_trace_epoll("rbtree is no existn");
			pthread_mutex_unlock(&ep- >mtx);
			return -1;
		}

		ep- >rbcnt --;
		free(epi);
		
		pthread_mutex_unlock(&ep- >mtx);

	} else if (op == EPOLL_CTL_MOD) {
		struct epitem tmp;
		tmp.sockfd = sockid;
		struct epitem *epi = RB_FIND(_epoll_rb_socket, &ep- >rbr, &tmp); //先在紅黑樹上找,根據(jù)key來找,也就是這個(gè)sockid,找的速度會非常快
		if (epi) {
			//紅黑樹上有該節(jié)點(diǎn),則修改對應(yīng)的事件
			epi- >event.events = event- >events;
			epi- >event.events |= EPOLLERR | EPOLLHUP;
		} else {
			errno = -ENOENT;
			return -1;
		}

	} else {
		nty_trace_epoll("op is no existn");
		assert(0);
	}

	return 0;
}

(3)epoll_wait()

//到雙向鏈表中去取相關(guān)的事件通知
int epoll_wait(int epid, struct epoll_event *events, int maxevents, int timeout) {

	nty_tcp_manager *tcp = nty_get_tcp_manager();
	if (!tcp) return -1;

	struct _nty_socket *epsocket = tcp- >fdtable- >sockfds[epid];

	struct eventpoll *ep = (struct eventpoll*)epsocket- >ep;
	
    // ...此處主要是一些負(fù)責(zé)驗(yàn)證性工作的代碼...

	//(1)當(dāng)eventpoll對象的雙向鏈表為空時(shí),程序會在這個(gè)while中等待一定時(shí)間,
	//直到有事件被觸發(fā),操作系統(tǒng)將epitem插入到雙向鏈表上使得rdnum >0時(shí),程序才會跳出while循環(huán)
	while (ep- >rdnum == 0 && timeout != 0) {
		// ...此處主要是一些與等待時(shí)間相關(guān)的代碼...
	}


	pthread_spin_lock(&ep- >lock);

	int cnt = 0;

	//(1)取得事件的數(shù)量
	//ep- >rdnum:代表雙向鏈表里邊的節(jié)點(diǎn)數(shù)量(也就是有多少個(gè)TCP連接來事件了)
	//maxevents:此次調(diào)用最多可以收集到maxevents個(gè)已經(jīng)就緒【已經(jīng)準(zhǔn)備好】的讀寫事件
	int num = (ep- >rdnum > maxevents ? maxevents : ep- >rdnum); //哪個(gè)數(shù)量少,就取得少的數(shù)字作為要取的事件數(shù)量
	int i = 0;
	
	while (num != 0 && !LIST_EMPTY(&ep- >rdlist)) { //EPOLLET

		//(2)每次都從雙向鏈表頭取得 一個(gè)一個(gè)的節(jié)點(diǎn)
		struct epitem *epi = LIST_FIRST(&ep- >rdlist);

		//(3)把這個(gè)節(jié)點(diǎn)從雙向鏈表中刪除【但這并不影響這個(gè)節(jié)點(diǎn)依舊在紅黑樹中】
		LIST_REMOVE(epi, rdlink); 

		//(4)這是個(gè)標(biāo)記,標(biāo)記這個(gè)節(jié)點(diǎn)【這個(gè)節(jié)點(diǎn)本身是已經(jīng)在紅黑樹中】已經(jīng)不在雙向鏈表中;
		epi- >rdy = 0;  //當(dāng)這個(gè)節(jié)點(diǎn)被操作系統(tǒng) 加入到 雙向鏈表中時(shí),這個(gè)標(biāo)記會設(shè)置為1。

		//(5)把事件標(biāo)記信息拷貝出來;拷貝到提供的events參數(shù)中
		memcpy(&events[i++], &epi- >event, sizeof(struct epoll_event));
		
		num --;
		cnt ++;       //拷貝 出來的 雙向鏈表 中節(jié)點(diǎn)數(shù)目累加
		ep- >rdnum --; //雙向鏈表里邊的節(jié)點(diǎn)數(shù)量減1
	}
	
	pthread_spin_unlock(&ep- >lock);

	//(5)返回 實(shí)際 發(fā)生事件的 tcp連接的數(shù)目;
	return cnt; 
}

該函數(shù)的邏輯也十分簡單,就是讓先看一下eventpoll對象的雙鏈表中是否有節(jié)點(diǎn)。如果有節(jié)點(diǎn)的話則取出節(jié)點(diǎn)中的事件填充到用戶傳入的指針?biāo)赶虻膬?nèi)存中。如果沒有節(jié)點(diǎn)的話,則在while循環(huán)中等待一定時(shí)間,直到有事件被觸發(fā)后操作系統(tǒng)會將epitem插入到雙向鏈表上使得rdnum>0時(shí)(這個(gè)過程是由操作系統(tǒng)調(diào)用epoll_event_callback函數(shù)完成的),程序才會跳出while循環(huán),去雙向鏈表中取數(shù)據(jù)。

(4)epoll_event_callback()

通過跟蹤epoll_event_callback在內(nèi)核中被調(diào)用的位置??芍?dāng)服務(wù)器在以下5種情況會調(diào)用epoll_event_callback:

  1. 客戶端connect()連入,服務(wù)器處于SYN_RCVD狀態(tài)時(shí)
  2. 三路握手完成,服務(wù)器處于ESTABLISHED狀態(tài)時(shí)
  3. 客戶端close()斷開連接,服務(wù)器處于FIN_WAIT_1和FIN_WAIT_2狀態(tài)時(shí)
  4. 客戶端send/write()數(shù)據(jù),服務(wù)器可讀時(shí)
  5. 服務(wù)器可以發(fā)送數(shù)據(jù)時(shí)

接下來,我們來看一下epoll_event_callback的源碼:

//當(dāng)發(fā)生客戶端三路握手連入、可讀、可寫、客戶端斷開等情況時(shí),操作系統(tǒng)會調(diào)用這個(gè)函數(shù),用以往雙向鏈表中增加一個(gè)節(jié)點(diǎn)【該節(jié)點(diǎn)同時(shí) 也在紅黑樹中】
int epoll_event_callback(struct eventpoll *ep, int sockid, uint32_t event) {
	struct epitem tmp;
	tmp.sockfd = sockid;

	//(1)根據(jù)給定的key【這個(gè)TCP連接的socket】從紅黑樹中找到這個(gè)節(jié)點(diǎn)
	struct epitem *epi = RB_FIND(_epoll_rb_socket, &ep- >rbr, &tmp);
	if (!epi) {
		nty_trace_epoll("rbtree not existn");
		assert(0);
	}

	//(2)從紅黑樹中找到這個(gè)節(jié)點(diǎn)后,判斷這個(gè)節(jié)點(diǎn)是否已經(jīng)被連入到雙向鏈表里【判斷的是rdy標(biāo)志】
	if (epi- >rdy) {
		//這個(gè)節(jié)點(diǎn)已經(jīng)在雙向鏈表里,那無非是把新發(fā)生的事件標(biāo)志增加到現(xiàn)有的事件標(biāo)志中
		epi- >event.events |= event;
		return 1;
	} 

	//走到這里,表示 雙向鏈表中并沒有這個(gè)節(jié)點(diǎn),那要做的就是把這個(gè)節(jié)點(diǎn)連入到雙向鏈表中

	nty_trace_epoll("epoll_event_callback -- > %dn", epi- >sockfd);
	
	pthread_spin_lock(&ep- >lock);

	//(3)標(biāo)記這個(gè)節(jié)點(diǎn)已經(jīng)被放入雙向鏈表中,我們剛才研究epoll_wait()的時(shí)候,從雙向鏈表中把這個(gè)節(jié)點(diǎn)取走的時(shí)候,這個(gè)標(biāo)志被設(shè)置回了0
	epi- >rdy = 1;  

	//(4)把這個(gè)節(jié)點(diǎn)鏈入到雙向鏈表的表頭位置
	LIST_INSERT_HEAD(&ep- >rdlist, epi, rdlink);

	//(5)雙向鏈表中的節(jié)點(diǎn)數(shù)量加1,剛才研究epoll_wait()的時(shí)候,從雙向鏈表中把這個(gè)節(jié)點(diǎn)取走的時(shí)候,這個(gè)數(shù)量減了1
	ep- >rdnum ++;

	pthread_spin_unlock(&ep- >lock);
	pthread_mutex_lock(&ep- >cdmtx);
	pthread_cond_signal(&ep- >cond);
	pthread_mutex_unlock(&ep- >cdmtx);

	return 0;
}

以上代碼的邏輯也十分簡單,就是將eventpoll所指向的紅黑樹的節(jié)點(diǎn)插入到雙向鏈表中。

總結(jié)

epoll底層實(shí)現(xiàn)中有兩個(gè)關(guān)鍵的數(shù)據(jù)結(jié)構(gòu),一個(gè)是eventpoll另一個(gè)是epitem,其中eventpoll中有兩個(gè)成員變量分別是rbr和rdlist,前者指向一顆紅黑樹的根,后者指向雙向鏈表的頭。而epitem則是紅黑樹節(jié)點(diǎn)和雙向鏈表節(jié)點(diǎn)的綜合體,也就是說epitem即可作為樹的節(jié)點(diǎn),又可以作為鏈表的節(jié)點(diǎn),并且epitem中包含著用戶注冊的事件。

  • 當(dāng)用戶調(diào)用epoll_create()時(shí),會創(chuàng)建eventpoll對象(包含一個(gè)紅黑樹和一個(gè)雙鏈表);
  • 而用戶調(diào)用epoll_ctl(ADD)時(shí),會在紅黑樹上增加節(jié)點(diǎn)(epitem對象);
  • 接下來,操作系統(tǒng)會默默地在通過epoll_event_callback()來管理eventpoll對象。當(dāng)有事件被觸發(fā)時(shí),操作系統(tǒng)則會調(diào)用epoll_event_callback函數(shù),將含有該事件的epitem添加到雙向鏈表中。
  • 當(dāng)用戶需要管理連接時(shí),只需通過epoll_wait()從eventpoll對象中的雙鏈表下"摘取"epitem并取出其包含的事件即可。
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4256

    瀏覽量

    62224
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4694

    瀏覽量

    68078
  • 協(xié)議棧
    +關(guān)注

    關(guān)注

    2

    文章

    138

    瀏覽量

    33592
  • epoll
    +關(guān)注

    關(guān)注

    0

    文章

    28

    瀏覽量

    2940
收藏 人收藏

    評論

    相關(guān)推薦

    epoll的使用

    以下內(nèi)容是參考華清遠(yuǎn)見《linux/unix系統(tǒng)編程手冊》對epoll的一個(gè)個(gè)人總結(jié),是我在華清遠(yuǎn)見比較全面的總結(jié)。一、epoll的優(yōu)點(diǎn)同I/O多路復(fù)用和信號驅(qū)動I/O一樣,linux的epoll
    發(fā)表于 05-11 13:22

    我讀過的最好的epoll講解

    的select以及epoll)處理甚至直接忽略。 為了避免CPU空轉(zhuǎn),可以引進(jìn)了一個(gè)代理(一開始有一位叫做select的代理,后來又有一位叫做poll的代理,不過兩者的本質(zhì)是一樣的)。這個(gè)代理比較厲害
    發(fā)表于 05-12 15:30

    epoll使用方法與poll的區(qū)別

    因?yàn)?b class='flag-5'>epoll的觸發(fā)機(jī)制是在內(nèi)核中直接完成整個(gè)功能 那個(gè)事件準(zhǔn)備就緒我就直接返回這個(gè)IO事件
    發(fā)表于 07-31 10:03

    epoll_wait的事件返回的fd為錯(cuò)誤是怎么回事?

    netlink 的 socket 連接 的 fd 為18,但是添加到epollepoll_wait()返回的fd 為 0為什么會出現(xiàn)這樣的現(xiàn)象?補(bǔ)充 說明:1、 epoll_wait返回
    發(fā)表于 06-12 09:03

    揭示EPOLL一些原理性的東西

    事件交給其他對象(后文介紹的select以及epoll)處理甚至直接忽略。為了避免CPU空轉(zhuǎn),可以引進(jìn)了一個(gè)代理(一開始有一位叫做select的代理,后來又有一位叫做poll的代理,不過兩者的本質(zhì)是一樣
    發(fā)表于 08-24 16:32

    【米爾王牌產(chǎn)品MYD-Y6ULX-V2開發(fā)板試用體驗(yàn)】socket通信和epoll

    ;gt;#include <sys/epoll.h>#include "ssd1306.h"const int PORT = 8888
    發(fā)表于 11-10 15:31

    uboot源碼分析,思路還算清晰

    uboot源碼分析,思路還算清晰
    發(fā)表于 10-24 15:25 ?19次下載
    uboot<b class='flag-5'>源碼</b><b class='flag-5'>分析</b>,思路還算清晰

    關(guān)于Epoll,你應(yīng)該知道的那些細(xì)節(jié)

    Epoll,位于頭文件sys/epoll.h,是Linux系統(tǒng)上的I/O事件通知基礎(chǔ)設(shè)施。epoll API為Linux系統(tǒng)專有,于內(nèi)核2.5.44中首次引入,glibc于2.3.2版本加入支持。其它提供類似的功能的系統(tǒng),包括F
    發(fā)表于 05-12 09:25 ?1161次閱讀

    poll&&epollepoll實(shí)現(xiàn)

    poll&&epollepoll實(shí)現(xiàn)
    發(fā)表于 05-14 14:34 ?2759次閱讀
    poll&&<b class='flag-5'>epoll</b>之<b class='flag-5'>epoll</b>實(shí)現(xiàn)

    Linux中epoll IO多路復(fù)用機(jī)制

    epoll 是Linux內(nèi)核中的一種可擴(kuò)展IO事件處理機(jī)制,最早在 Linux 2.5.44內(nèi)核中引入,可被用于代替POSIX select 和 poll 系統(tǒng)調(diào)用,并且在具有大量應(yīng)用程序請求時(shí)能夠
    發(fā)表于 05-16 16:07 ?685次閱讀
    Linux中<b class='flag-5'>epoll</b> IO多路復(fù)用機(jī)制

    Java反射的工作原理和源碼分析

    Java反射的工作原理和源碼分析
    發(fā)表于 07-08 15:11 ?14次下載
    Java反射的工作原理和<b class='flag-5'>源碼</b><b class='flag-5'>分析</b>

    一文詳解epoll的實(shí)現(xiàn)原理

    本文以四個(gè)方面介紹epoll的實(shí)現(xiàn)原理,1.epoll的數(shù)據(jù)結(jié)構(gòu);2.協(xié)議棧如何與epoll通信;3.epoll線程安全如何加鎖;4.ET與LT的實(shí)現(xiàn)。
    的頭像 發(fā)表于 08-01 13:28 ?3915次閱讀

    epoll來實(shí)現(xiàn)多路復(fù)用

    本人用epoll來實(shí)現(xiàn)多路復(fù)用,epoll觸發(fā)模式有兩種: ET(邊緣模式) LT(水平模式) LT模式 是標(biāo)準(zhǔn)模式,意味著每次epoll_wait()返回后,事件處理后,如果之后還有數(shù)據(jù),會不斷
    的頭像 發(fā)表于 11-09 10:15 ?434次閱讀
    用<b class='flag-5'>epoll</b>來實(shí)現(xiàn)多路復(fù)用

    epoll 的實(shí)現(xiàn)原理

    今兒我們就從源碼入手,來幫助大家簡單理解一下 epoll 的實(shí)現(xiàn)原理,并在后邊分析一下,大家都說 epoll 性能好,那到底是好在哪里。 epoll
    的頭像 發(fā)表于 11-09 11:14 ?467次閱讀
    <b class='flag-5'>epoll</b> 的實(shí)現(xiàn)原理

    epoll的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

    一、epoll的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu) 在開始研究源代碼之前,我們先看一下 epoll 中使用的數(shù)據(jù)結(jié)構(gòu),分別是 eventpoll、epitem 和 eppoll_entry。 1、eventpoll 我們
    的頭像 發(fā)表于 11-10 10:20 ?698次閱讀
    <b class='flag-5'>epoll</b>的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)