epoll 相關(guān)
標(biāo)簽(空格分隔): linux c/c++
1.epoll_create調(diào)用
int epoll_create(int size);
int epoll_create1(int flags);
- 第一個(gè)函數(shù)epoll_create調(diào)用是比較常用的調(diào)用,第二個(gè)調(diào)用是改進(jìn)版本。內(nèi)核版本在2.9以及之后才能夠使用婶溯。
- 調(diào)用成功的返回值,是一個(gè)文件描述符(非負(fù)整數(shù)),指向一個(gè)epoll實(shí)例绳泉,這個(gè)文件描述符代表這后續(xù)對(duì)于epoll相關(guān)接口的引用蓄氧。需要在使用結(jié)束后調(diào)用close關(guān)閉文件描述符弧满。
- 調(diào)用出現(xiàn)錯(cuò)誤的返回值是-1,并可以在全局變量error中查看錯(cuò)誤信息俊庇。
- 第一個(gè)調(diào)用的參數(shù)size是,調(diào)用者在后續(xù)使用epoll添加感興趣的文件描述符個(gè)數(shù)的大小甲葬,這個(gè)是一個(gè)給系統(tǒng)初次分配epoll監(jiān)控文件描述符數(shù)據(jù)結(jié)構(gòu)的內(nèi)存空間的一個(gè)參考值廊勃,但是如果后來(lái)調(diào)用者,監(jiān)聽(tīng)的事件超過(guò)這個(gè)范圍演顾,那么系統(tǒng)會(huì)額外的分配空間的供搀。
總的來(lái)說(shuō)這個(gè)值只是操作系統(tǒng)的參考值。 - epoll_create1參數(shù)是一個(gè)文件描述符標(biāo)志钠至,如果為0那么和 epoll_create(0)一樣。
2 epoll_ctl調(diào)用
2.1函數(shù)原型
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
2.2參數(shù)說(shuō)明
2.2.1 event參數(shù)
結(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 */
};
- epoll_event中events變量為事件發(fā)生的類型胎源,可以是下面提到的事件類型EPOLLIN,EPOLLOUT,EPOLLHDUP,EPOLLPRI,EPOLLERR,EPOLLHUP,EPOLLET,EPOLLONESHOT,EPOLLWAKEUP中的一種棉钧,具體的參見(jiàn)下面的事件類型說(shuō)明。
- data為一個(gè)聯(lián)合體涕蚤,可以根據(jù)不同的事件宪卿,來(lái)表示用戶數(shù)據(jù)內(nèi)容。例如可以是一個(gè)文件描述符万栅。
2.2.2 fd參數(shù)
fd為需要監(jiān)控的文件描述符佑钾。在這里是根據(jù)這個(gè)文件描述符對(duì)后面的event結(jié)構(gòu)進(jìn)行操作的。具體見(jiàn)下面的op參數(shù).
2.2.3 op參數(shù)
- EPOLL_CTL_ADD:將文件描述符fd關(guān)聯(lián)到event結(jié)構(gòu)當(dāng)中,并把event事件添加到epfd實(shí)例當(dāng)中烦粒。相當(dāng)于把fd注冊(cè)到epoll實(shí)例當(dāng)中休溶。
- EPOLL_CTL_MOD:根據(jù)文件描述符fd,來(lái)找到fd在epoll實(shí)例當(dāng)中對(duì)應(yīng)的event結(jié)構(gòu),修改這個(gè)event結(jié)構(gòu)扰她。
- EPOLL_CTL_DEL:根據(jù)文件描述符fd兽掰,找到其所對(duì)應(yīng)的文件event結(jié)構(gòu),刪除這個(gè)fd上面的事件監(jiān)控徒役。
- 總結(jié)下孽尽,epoll實(shí)際是通過(guò)fd來(lái)構(gòu)建一個(gè)event事件,通過(guò)這個(gè)event結(jié)構(gòu)來(lái)監(jiān)控fd上面發(fā)生的文件事件操作忧勿。
2.2.4 epdf參數(shù)
epfd為epoll_create 或者epoll_create1函數(shù)調(diào)用的返回值杉女,實(shí)際為一個(gè)文件描述符,指向epoll實(shí)例鸳吸。epoll系統(tǒng)操作都是通過(guò)這個(gè)文件描述符來(lái)進(jìn)行的熏挎。
2.3返回值
- 調(diào)用成功返回0
- 失敗返回-1,并置error錯(cuò)誤信息层释。
3 epoll_wait調(diào)用
3.1函數(shù)原型
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events,
int maxevents, int timeout,const sigset_t *sigmask);
3.2參數(shù)說(shuō)明
3.2.1 timeout參數(shù)
- timeout參數(shù)指定了在沒(méi)有事件發(fā)生的時(shí)候epoll_wait調(diào)用阻塞的毫秒數(shù)(milliseconds)婆瓜。
- 如果把這個(gè)值設(shè)置為-1,那么在沒(méi)有事件發(fā)生時(shí),這個(gè)調(diào)用會(huì)永遠(yuǎn)的阻塞下去廉白。
- 如果timeout=0那么epoll_wait會(huì)檢查監(jiān)控的事件是否發(fā)生个初,然后立刻返回。
- 上面指的事件猴蹂,可以包含監(jiān)控的文件事件院溺,也可以是信號(hào)中斷事件。
3.2.2 maxevent參數(shù)
- maxevent,是一次調(diào)用epoll_wait可以返回有監(jiān)控事件發(fā)生的最大個(gè)數(shù)磅轻。
- 例如監(jiān)控的事件中在某一時(shí)刻可能有20個(gè)發(fā)生了珍逸,但是如果這個(gè)時(shí)候maxevent=10,那么只會(huì)返回10個(gè)發(fā)生的事件。
3.2.3 events參數(shù)
- events表示的是一個(gè)struct epoll_event數(shù)組聋溜,存放的是某個(gè)時(shí)刻發(fā)生事件的結(jié)構(gòu)體
- 可以在epoll_wait調(diào)用結(jié)束之后谆膳,來(lái)訪問(wèn)這個(gè)結(jié)構(gòu)體里面的內(nèi)容例如fd來(lái)處理發(fā)生的文件事件。
3.2.4 epfd參數(shù)
- epfd為epoll_create函數(shù)返回的文件描述符撮躁。epoll實(shí)例漱病。
3.3返回值
- 沒(méi)有任何事件發(fā)生,或者超時(shí)返回0把曼。
- 出現(xiàn)錯(cuò)誤返回-1杨帽,并設(shè)置error錯(cuò)誤信息。
- 返回監(jiān)控事件發(fā)生的個(gè)數(shù)嗤军。
4.使用方法
下面是一個(gè)處理多個(gè)客戶端連接的服務(wù)端程序,可以根據(jù)這個(gè)大體的框架和自己的情況進(jìn)行修改注盈。
#include<stdio.h>
#include<unistd.h>
#include<sys/epoll.h>
#define MAX_EVENTS 10
int main (int argc,char* argv[] ) {
struct epoll_event ev, events[MAX_EVENTS];
int listen_sock, conn_sock, nfds, epollfd;
/* Code to set up listening socket, 'listen_sock',
(socket(), bind(), listen()) omitted */
/*創(chuàng)建epoll實(shí)例*/
epollfd = epoll_create1(0);
if (epollfd == -1) {
perror("epoll_create1");
exit(EXIT_FAILURE);
}
/*設(shè)置epoll_event,關(guān)聯(lián)到epoll實(shí)例*/
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
/*注冊(cè)listen_sock到epoll實(shí)例*/
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
perror("epoll_ctl: listen_sock");
exit(EXIT_FAILURE);
}
for (;;) {
/*監(jiān)控事件的發(fā)生,-1表示檢查監(jiān)控的事件后立即返回*/
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_wait");
exit(EXIT_FAILURE);
}
/*遍歷返回的事件叙赚,對(duì)事件進(jìn)行處理*/
for (n = 0; n < nfds; ++n) {
/*如果是發(fā)生在接收連接的套接字上老客,那么接受客戶端連接,并監(jiān)控新建的連接文件事件*/
if (events[n].data.fd == listen_sock) {
conn_sock = accept(listen_sock,
(struct sockaddr *) &local, &addrlen);
if (conn_sock == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
setnonblocking(conn_sock);
/*設(shè)置新連接文件事件為讀寫事件*/
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
/*添加到epoll實(shí)例中纠俭,進(jìn)行監(jiān)控*/
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
&ev) == -1) {
perror("epoll_ctl: conn_sock");
exit(EXIT_FAILURE);
}
}/*如果發(fā)生的事件不是在接收連接的套接字上面*/
else {
/*處理產(chǎn)生的新的連接的數(shù)據(jù)沿量,例如,讀取客戶端寫的數(shù)據(jù)冤荆,或者向客戶端寫數(shù)據(jù)*/
do_use_fd(events[n].data.fd);
}
}
}
}
4.參考內(nèi)容
- Linux man epoll_create
- Linux man epoll_ctl
- Linux man epoll_wait
- Unix 網(wǎng)絡(luò)編程 卷I 套接字聯(lián)網(wǎng)API