epoll 與 select 的差異
- select() 有個問題,其最大個數限制 FD_SETSIZE,預設值可能是 1024 或 2048
- epoll 上限是系統最大可以打開文件的數目,執行 "cat /proc/sys/fs/file-max" 可檢視此上限值。在 Linux 2.6.28之後,要檢視 /proc/sys/fs/epoll/max_user_watches
- 另外 epoll 透用 mmap 讓 kernel space 與 user space 共享同一塊內存,減少內存拷貝。而 select() 則需要較多的內存拷貝。
epoll 支援兩種工作模式
LT(level triggered)
支援 block 和 no-block socket,在事件狀態未變更前將不斷被觸發。(直到緩衝區資料全部被讀取)ET(edge-triggered)
僅支援 no-block socket,在事件狀態改變時只觸發一次。
三個API
int epoll_create(int maxfds);
建立 epoll 文件描述符
int epoll_ctl (int epfd, int op, int fd, struct epoll_event *event);
增刪或修改文件描述符,這些描述符的集合又稱為 epoll set。
op 可以是 EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD
epoll_event 結構如下:
struct epoll_event
{
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
新增 event 時要設定事件以及文件描述符,如下:
setnonblocking(fd);
ev.events=EPOLLIN|EPOLLET;
ev.data.fd=fd;
// EPOLLET:工作模式設定為 edge-triggered,若不設定則是 level triggeredint epoll_wait(int epfd, epoll_event *events, int max events, int timeout)
// EPOLLONESHOT: 一個事件發生並且讀取之後,不再監聽此文件描述符
// EPOLLIN是監聽讀的事件,若需要監聽寫的事件,可加入EPOLLOUT
等待用戶感興趣的 IO事件發生, 若有事件發生會返回事件個數,並將事件放入 events。若要關閉 epoll 文件描述符, 直接使用 close() 即可。
程式範例
epollfd = epoll_create1(0); event.events = EPOLLIN; event.data.fd = serverfd; epoll_ctl(epollfd, EPOLL_CTL_ADD, serverfd, &event); while(true) { nfds = epoll_wait(epollfd, &events, MAXEVENTS, timeout); for(i = 0; i < nfds; ++i) { if(events[i].data.fd == serverfd) { conn_sock = accpet(listen_sock,(struct sockaddr *) &addr, &addrlen); setnonblocking(conn_sock); ev.events = EPOLLIN | EPOLLET; ev.data.fd = conn_sock; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { perror("epoll_ctl: conn_sock"); exit(EXIT_FAILURE); } } else { do_use_fd(events[n].data.fd); } } }
參考資料