日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

linux网络编程系列-select和epoll的区别

發(fā)布時(shí)間:2023/12/10 linux 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux网络编程系列-select和epoll的区别 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

select和epoll屬于I/O多路復(fù)用模型,用于持續(xù)監(jiān)聽(tīng)多個(gè)socket,獲取其IO事件。

select(輪詢)

該模型輪詢各socket,不管socket是否活躍,隨著socket數(shù)的增加,性能逐漸下降。

?

#include <sys/select.h> #include <sys/time.h> int select (int maxfdpl, fd_set* readset, fd_set* writeset, fd_set* exceptset, const struct timeval* timeout)

調(diào)用時(shí)輪詢一次所有描述字,超時(shí)時(shí)再輪詢一次。如果沒(méi)有描述字準(zhǔn)備好,則返回0;中途錯(cuò)誤返回-1;有描述字準(zhǔn)備好,則將其對(duì)應(yīng)位置為1,其他描述字置為0,返回準(zhǔn)備好的描述字個(gè)數(shù)。

fd_set:整數(shù)數(shù)組,每個(gè)數(shù)中的每一位對(duì)應(yīng)一個(gè)描述字,其具體大小有內(nèi)核的FD_SETSIZE決定,默認(rèn)值為1024。

void FD_ZERO(fd_set* fdset): clear all bits in fdset void FD_SET(int fd, fd_set* fdset):turn on the bit for fd in fdset void FD_CLR(int fd, fd_set* fdset):turn off the bit for fd in fdset int FD_ISSET(int fd, fd_set* fdset):is the bit for fd on in fdset

?

epoll(觸發(fā))

epoll采用了中斷注冊(cè)回調(diào)的方式,socket IO就緒時(shí)發(fā)出中斷,然后將socket加入就緒隊(duì)列。由三個(gè)系統(tǒng)調(diào)用:epoll_create,epoll_ctl,epoll_wait。

能顯著提高程序在大量并發(fā)連接中只有少量活躍的情況下的系統(tǒng)CPU利用率:它會(huì)復(fù)用文件描述符集合來(lái)傳遞結(jié)果,不需要每次等待事件之前都重新準(zhǔn)備要被偵聽(tīng)的文件描述符集合;獲取事件的時(shí)候,它無(wú)須遍歷整個(gè)被偵聽(tīng)的描述符集,只要遍歷那些被內(nèi)核IO事件異步喚醒而加入Ready隊(duì)列的描述符集合。

select/epoll都需要在內(nèi)核和用戶空間之間復(fù)制數(shù)據(jù),epoll使用了內(nèi)存映射(mmap)技術(shù),將內(nèi)核和用戶空間指向同一塊內(nèi)存。

系列函數(shù):

創(chuàng)建函數(shù)

創(chuàng)建一個(gè)epoll句柄,size-監(jiān)聽(tīng)套接字的數(shù)。當(dāng)創(chuàng)建好epoll句柄后,會(huì)占用一個(gè)fd值,所以在使用完epoll后,必須調(diào)用close()關(guān)閉,否則可能導(dǎo)致fd被耗盡。

?

#include <sys/epoll.h> int epoll_create(int size)

?

事件注冊(cè)函數(shù)

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

第一個(gè)參數(shù)是epoll_create()的返回值;
第二個(gè)參數(shù)表示動(dòng)作,用三個(gè)宏來(lái)表示:
EPOLL_CTL_ADD:注冊(cè)新的fd到epfd中,
EPOLL_CTL_MOD:修改已經(jīng)注冊(cè)的fd的監(jiān)聽(tīng)事件,
EPOLL_CTL_DEL:從epfd中刪除一個(gè)fd;
第三個(gè)參數(shù)是需要監(jiān)聽(tīng)的fd;
第四個(gè)參數(shù)是告訴內(nèi)核監(jiān)聽(tīng)事件,struct epoll_event結(jié)構(gòu)如下:

typedef union epoll_data { void *ptr; int fd; __uint32_t u32; __uint64_t u64; } epoll_data_t; struct epoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ };


events可以是以下幾個(gè)宏的集合:
EPOLLIN :表示對(duì)應(yīng)的文件描述符可以讀(包括對(duì)端SOCKET正常關(guān)閉);
EPOLLOUT:表示對(duì)應(yīng)的文件描述符可以寫;
EPOLLPRI:表示對(duì)應(yīng)的文件描述符有緊急的數(shù)據(jù)可讀(這里應(yīng)該表示有帶外數(shù)據(jù)到來(lái));
EPOLLERR:表示對(duì)應(yīng)的文件描述符發(fā)生錯(cuò)誤;
EPOLLHUP:表示對(duì)應(yīng)的文件描述符被掛斷;
EPOLLET: 將EPOLL設(shè)為邊緣觸發(fā)(Edge Triggered)模式,這是相對(duì)于水平觸發(fā)(Level Triggered)來(lái)說(shuō)的。ET只有新事件到來(lái)時(shí),epoll_wait才能獲得通知,即使緩沖區(qū)中還有數(shù)據(jù),epoll_wait也無(wú)法再獲得改描述符的事件;LT只要對(duì)應(yīng)的緩沖區(qū)中還有數(shù)據(jù),epoll_wait就可以獲得該描述符對(duì)應(yīng)的事件。
EPOLLONESHOT:只監(jiān)聽(tīng)一次事件,當(dāng)監(jiān)聽(tīng)完這次事件之后,如果還需要繼續(xù)監(jiān)聽(tīng)這個(gè)socket的話,需要再次把這個(gè)socket加入到EPOLL隊(duì)列里


使用如下:

?

struct epoll_event ev; ev.data.fd=listenfd; ev.events=EPOLLIN|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);


等待函數(shù)

?

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)


等待事件的產(chǎn)生,參數(shù)events用來(lái)從內(nèi)核得到事件集合。maxevents告之內(nèi)核這個(gè)events有多大,這個(gè)maxevents的值不能大于創(chuàng)建epoll_create()時(shí)的size,參數(shù)timeout是超時(shí)時(shí)間(毫秒,0會(huì)立即返回,-1永久阻塞)。該函數(shù)返回需要處理的事件數(shù)目,如返回0表示已超時(shí)。
注意:某fd上發(fā)生事件后,其事件類型會(huì)被清空,所以如果下一個(gè)循環(huán)還要關(guān)注這個(gè)socket fd的話,則需要用epoll_ctl(epfd,EPOLL_CTL_MOD,listenfd,&ev)來(lái)重新設(shè)置socket fd的事件類型。這時(shí)不用EPOLL_CTL_ADD,因?yàn)閟ocket fd并未清空,只是事件類型清空。這一步非常重要。


實(shí)例

?

struct epoll_event ev, *events;for(;;) {nfds = epoll_wait(kdpfd, events, maxevents, -1);for(n = 0; n < nfds; ++n) {if(events[n].data.fd == listener) {client = accept(listener, (struct sockaddr *) &local,&addrlen);if(client < 0){perror("accept");continue;}setnonblocking(client);ev.events = EPOLLIN | EPOLLET;ev.data.fd = client;if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) {fprintf(stderr, "epoll set insertion error: fd=%d\n",client);return -1;}} else {do_use_fd(events[n].data.fd);}} }

對(duì)比:
select - 如果同時(shí)建立很多連接,但只有少數(shù)事件發(fā)生,這種輪詢會(huì)造成效率很低;頻繁從內(nèi)核拷貝、復(fù)制描述字;監(jiān)聽(tīng)描述字受限于內(nèi)核的FD_SETSIZE;
epoll - 這種回調(diào)觸發(fā)式操作會(huì)保證效率;不需要頻繁的拷貝;監(jiān)聽(tīng)描述字沒(méi)有限止,只與系統(tǒng)資源有關(guān);epoll返回時(shí)已經(jīng)明確的知道哪個(gè)sokcet fd發(fā)生了事件,不用再一個(gè)個(gè)比對(duì)。

?

轉(zhuǎn)載于:https://www.cnblogs.com/whuqin/archive/2013/05/09/4982011.html

總結(jié)

以上是生活随笔為你收集整理的linux网络编程系列-select和epoll的区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。