epoll 相關(guān)
標簽(空格分隔): linux c/c++
1.epoll_create調(diào)用
int epoll_create(int size);
int epoll_create1(int flags);
- 第一個函數(shù)epoll_create調(diào)用是比較常用的調(diào)用,第二個調(diào)用是改進版本。內(nèi)核版本在2.9以及之后才能夠使用。
- 調(diào)用成功的返回值,是一個文件描述符(非負整數(shù)),指向一個epoll實例,這個文件描述符代表這后續(xù)對于epoll相關(guān)接口的引用。需要在使用結(jié)束后調(diào)用close關(guān)閉文件描述符。
- 調(diào)用出現(xiàn)錯誤的返回值是-1,并可以在全局變量error中查看錯誤信息。
- 第一個調(diào)用的參數(shù)size是,調(diào)用者在后續(xù)使用epoll添加感興趣的文件描述符個數(shù)的大小,這個是一個給系統(tǒng)初次分配epoll監(jiān)控文件描述符數(shù)據(jù)結(jié)構(gòu)的內(nèi)存空間的一個參考值,但是如果后來調(diào)用者,監(jiān)聽的事件超過這個范圍,那么系統(tǒng)會額外的分配空間的。
總的來說這個值只是操作系統(tǒng)的參考值。 - epoll_create1參數(shù)是一個文件描述符標志,如果為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ù)說明
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中的一種,具體的參見下面的事件類型說明。
- data為一個聯(lián)合體,可以根據(jù)不同的事件,來表示用戶數(shù)據(jù)內(nèi)容。例如可以是一個文件描述符。
2.2.2 fd參數(shù)
fd為需要監(jiān)控的文件描述符。在這里是根據(jù)這個文件描述符對后面的event結(jié)構(gòu)進行操作的。具體見下面的op參數(shù).
2.2.3 op參數(shù)
- EPOLL_CTL_ADD:將文件描述符fd關(guān)聯(lián)到event結(jié)構(gòu)當中,并把event事件添加到epfd實例當中。相當于把fd注冊到epoll實例當中。
- EPOLL_CTL_MOD:根據(jù)文件描述符fd,來找到fd在epoll實例當中對應的event結(jié)構(gòu),修改這個event結(jié)構(gòu)。
- EPOLL_CTL_DEL:根據(jù)文件描述符fd,找到其所對應的文件event結(jié)構(gòu),刪除這個fd上面的事件監(jiān)控。
- 總結(jié)下,epoll實際是通過fd來構(gòu)建一個event事件,通過這個event結(jié)構(gòu)來監(jiān)控fd上面發(fā)生的文件事件操作。
2.2.4 epdf參數(shù)
epfd為epoll_create 或者epoll_create1函數(shù)調(diào)用的返回值,實際為一個文件描述符,指向epoll實例。epoll系統(tǒng)操作都是通過這個文件描述符來進行的。
2.3返回值
- 調(diào)用成功返回0
- 失敗返回-1,并置error錯誤信息。
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ù)說明
3.2.1 timeout參數(shù)
- timeout參數(shù)指定了在沒有事件發(fā)生的時候epoll_wait調(diào)用阻塞的毫秒數(shù)(milliseconds)。
- 如果把這個值設置為-1,那么在沒有事件發(fā)生時,這個調(diào)用會永遠的阻塞下去。
- 如果timeout=0那么epoll_wait會檢查監(jiān)控的事件是否發(fā)生,然后立刻返回。
- 上面指的事件,可以包含監(jiān)控的文件事件,也可以是信號中斷事件。
3.2.2 maxevent參數(shù)
- maxevent,是一次調(diào)用epoll_wait可以返回有監(jiān)控事件發(fā)生的最大個數(shù)。
- 例如監(jiān)控的事件中在某一時刻可能有20個發(fā)生了,但是如果這個時候maxevent=10,那么只會返回10個發(fā)生的事件。
3.2.3 events參數(shù)
- events表示的是一個struct epoll_event數(shù)組,存放的是某個時刻發(fā)生事件的結(jié)構(gòu)體
- 可以在epoll_wait調(diào)用結(jié)束之后,來訪問這個結(jié)構(gòu)體里面的內(nèi)容例如fd來處理發(fā)生的文件事件。
3.2.4 epfd參數(shù)
- epfd為epoll_create函數(shù)返回的文件描述符。epoll實例。
3.3返回值
- 沒有任何事件發(fā)生,或者超時返回0。
- 出現(xiàn)錯誤返回-1,并設置error錯誤信息。
- 返回監(jiān)控事件發(fā)生的個數(shù)。
4.使用方法
下面是一個處理多個客戶端連接的服務端程序,可以根據(jù)這個大體的框架和自己的情況進行修改。
#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實例*/
epollfd = epoll_create1(0);
if (epollfd == -1) {
perror("epoll_create1");
exit(EXIT_FAILURE);
}
/*設置epoll_event,關(guān)聯(lián)到epoll實例*/
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
/*注冊listen_sock到epoll實例*/
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);
}
/*遍歷返回的事件,對事件進行處理*/
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);
/*設置新連接文件事件為讀寫事件*/
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
/*添加到epoll實例中,進行監(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)絡編程 卷I 套接字聯(lián)網(wǎng)API