struct epoll_event {
? ? __uint32_t events;? ? ? /* Epoll events */
? ? epoll_data_t data;? ? ? /* User data variable */
};
一、函數(shù)解析
#include <sys/epoll.h>
int epoll_create(int size)
1. size不是最大值怖辆,而是內(nèi)核如何對(duì)內(nèi)部結(jié)構(gòu)進(jìn)行維度設(shè)置的提示拱撵。
2. epoll_create返回的文件描述符必須使用close關(guān)閉螺垢。
返回值:成功(非負(fù)文件描述符) 失斎右邸(-1)
errno(EINVAL-size非正 | ENFILE-文件描述符用完 | ENOMEM-內(nèi)存不足)
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)?
events成員有:
EPOLLIN 關(guān)聯(lián)的文件描述符可讀
EPOLLOUT 關(guān)聯(lián)的文件描述符可寫(xiě)
EPOLLRDHUP 流式套接字對(duì)端關(guān)閉連接或關(guān)閉寫(xiě)通道(ET模式寫(xiě)非常有用)2.6.17
EPOLLPRI 關(guān)聯(lián)的文件描述符緊急數(shù)據(jù)可讀
EPOLLERR 關(guān)聯(lián)的文件描述符發(fā)生錯(cuò)誤
EPOLLHUP? 關(guān)聯(lián)的文件描述符掛起
EPOLLET ET模式
EPOLLONESHOT 關(guān)聯(lián)的文件描述符設(shè)置一次性行為 2.6.2
op操作有:
EPOLL_CTL_ADD 增加
EPOLL_CTL_MOD 修改
EPOLL_CTL_DEL 刪除
返回值:成功(0) 失斔癫(-1)
errno(EBADF-epfd或者fd不是合法的 | EEXIST-重復(fù)增加 | EINVAL-epfd不是epoll描述符或者epfd=fd | ENOENT-修改刪除的fd不在epoll中 | ENOMEM-內(nèi)存不足 | EPERM-fd不支持epoll)
#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);
1. timeout為0表示立馬返回倦畅, 為-1表示無(wú)限等待
2. 超時(shí)或者達(dá)到maxevents都會(huì)返回
返回值:成功(就緒的文件描述符數(shù)量) 失敱乒辍(-1)
errno(EBADF-epfd不合法 | EFAULT-events沒(méi)有寫(xiě)權(quán)限 | EINTR-超時(shí) | EINVAL-epfd不是epoll描述符或者maxevents小于0)?
二、寫(xiě)過(guò)程
水平觸發(fā)(LT):只要寫(xiě)緩沖區(qū)還有空間真仲,就返回寫(xiě)就緒喇颁。
邊緣觸發(fā)(ET):
? ? 1.首次加入epoll且寫(xiě)緩沖區(qū)有空間漏健,返回寫(xiě)就緒(參考四用例第一次調(diào)用printf)
? ? 2.寫(xiě)緩沖區(qū)內(nèi)容被取走,返回寫(xiě)就緒(參考四用例的fflush橘霎,\n有類(lèi)似作用)
? ? 3.EPOLL_CTL_MOD修改關(guān)聯(lián)文件描述符event蔫浆,且寫(xiě)緩沖區(qū)有空間,返回寫(xiě)就緒(參考四用例epoll_ctl)
三姐叁、讀過(guò)程
水平觸發(fā):只要讀緩沖區(qū)有數(shù)據(jù)瓦盛,就返回可讀。
邊緣觸發(fā):
? ? 數(shù)據(jù)到來(lái)的時(shí)候返回可讀外潜。(即如果上一次沒(méi)有讀完的數(shù)據(jù)原环,需要等到下一次數(shù)據(jù)到來(lái)的時(shí)候才能繼續(xù)讀)。
四处窥、用例(寫(xiě)過(guò)程)
#include <stdio.h>
#include <sys/epoll.h>
#define STDOUT_FILENO 1
int main(void) {
? int epfd, nfds;
? struct epoll_event ev, events[5]; //ev用于注冊(cè)事件嘱吗,數(shù)組用于返回要處理的事件
? epfd = epoll_create(1); //只需要監(jiān)聽(tīng)一個(gè)描述符——標(biāo)準(zhǔn)輸出
? ev.data.fd = STDOUT_FILENO;
? ev.events = EPOLLOUT | EPOLLET; //監(jiān)聽(tīng)讀狀態(tài)同時(shí)設(shè)置ET模式
? epoll_ctl(epfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev); //注冊(cè)epoll事件
? for (;;) {
? ? nfds = epoll_wait(epfd, events, 5, -1);
? ? for (int i = 0; i < nfds; i++) {
? ? ? ?if (events[i].data.fd == STDOUT_FILENO) {
? ? ? ? ? ?printf( "hello world!");
// ? ? ? ? ev.data.fd=STDOUT_FILENO;
// ? ? ? ? ev.events=EPOLLOUT|EPOLLET;
// ? ? ? ? epoll_ctl(epfd,EPOLL_CTL_MOD,STDOUT_FILENO,&ev); //重新MOD事件(ADD無(wú)效),返回寫(xiě)就緒滔驾,循環(huán)輸出
//? ? ? ? ?fflush(stdout); //讀取寫(xiě)緩沖區(qū)數(shù)據(jù)谒麦,返回寫(xiě)就緒,循環(huán)輸出
}}}}
五哆致、如何判斷客戶(hù)端關(guān)閉連接
1. TCP recv返回0, 說(shuō)明對(duì)方關(guān)閉
2. 注冊(cè)EPOLLERR, 收到事件是關(guān)閉
3. recv/send 返回-1時(shí), 如果錯(cuò)誤不是EWOULDBLOCK或者EINTR, 也主動(dòng)關(guān)閉連接绕德。