epoll 實現 I/O 複用
阿新 • • 發佈:2020-12-09
epoll
#include <sys/epoll.h> int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
epoll 的核心觀念就是 epoll instance (epoll 例項)
可以把它看成是包含兩個連結串列的容器
●想要監聽的檔案描述符的連結串列
●準備好了的檔案描述符連結串列
epoll_create
int epoll_create(int size);
int epoll_create1(int flags)
使用 epoll_create 建立 epoll instance 並返回指向它的檔案描述符,引數 size 不僅沒用還不能為 0
使用 epoll_create1(0) 相當於正確使用 epoll_create。
出錯返回 -1
epoll_ctl
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
用於對監聽的那條連結串列進行增,刪,改操作。
●epfd 是 epoll instace 的檔案描述符
●op 可能以下值
EPOLL_CTL_ADD 增加要監聽的檔案描述符
EPOLL_CTL_MOD
EPOLL_CTL_DEL
●fd 想要監聽的檔案描述符
●event 的結構體內容如下
typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t; structepoll_event { uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ };
uint32_t events 可能是以下值
EPOLLIN 有資料可讀
EPOLLOUT 可以寫資料
在增加描述符 fd 時,把 data.fd 設定成 fd
epoll_tcl 成功返回 0 ,失敗返回 -1
epoll_wait
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
等待描述符就修,會將準備好的檔案描述符儲存在結構體陣列中,其地址由 events 返回
最多 maxevents 個準備好的描述符
timeout 負數代表 一直等待
使用 epoll 替代 poll
#include <stdio.h> #include <netdb.h> #include <unistd.h> #include <string.h> #include <poll.h> #include <errno.h> #include <sys/epoll.h> #include <stdlib.h> #define MAXLINE 1024 #define MAX_EVENTS 10000 int main(int argc, char *argv[]) { char buf[MAXLINE]; int listenfd, clientfd; int i, nread; struct sockaddr_in sock; socklen_t socklen; int epollfd, nready; struct epoll_event ev, events[MAX_EVENTS]; listenfd = socket(AF_INET, SOCK_STREAM, 0); if(listenfd < 0) { perror("socket error:"); return -1; } memset(&sock, 0, sizeof(sock)); sock.sin_family = AF_INET; sock.sin_addr.s_addr = htonl(INADDR_ANY); sock.sin_port = htons(18888); socklen = sizeof(sock); if(bind(listenfd, (struct sockaddr *)&sock, socklen) != 0) { perror("bind error:"); return -1; } if(listen(listenfd, 1024) != 0) { perror("listen error\n"); return -1; } epollfd = epoll_create1(0); if(epollfd < 0) { perror("epoll_create1 error:"); return -1; } ev.events = EPOLLIN; ev.data.fd = listenfd; if(epoll_ctl(epollfd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) { perror("epoll_ctl errpr"); return -1; } for(;;) { nready = epoll_wait(epollfd, events, MAX_EVENTS, -1); if(nready == -1) { perror("epoll_wait error: "); return -1; } for(i = 0; i < nready; i++) { if(events[i].data.fd == listenfd) { clientfd = accept(listenfd, NULL, NULL); if(clientfd < 0) { perror("accept error: "); return -1; } ev.events = EPOLLIN; ev.data.fd = clientfd; if(epoll_ctl(epollfd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) { perror("epoll_ctl error: "); return -1; } } else { nread = read(events[i].data.fd, buf, MAXLINE - 1); if(nread < -1) { perror("read error: "); return -1; } else if(nread == 0) { if(epoll_ctl(epollfd, EPOLL_CTL_DEL, events[i].data.fd, &events[i]) == -1) { perror("epoll_ctl error: "); return -1; } continue; } buf[nread] = '\0'; printf("%s\n", buf); } } } return 0; }
short events;