目录
epoll原理
epoll_create
epoll_ctl
epoll_wait
代码示例
参考资料
epoll原理
epoll_create
该函数生成一个epoll专用的文件描述符。
int epoll_create(int size);
-
size:epoll上能关注的最大文件描述符数
epoll_ctl
用于控制某个epoll文件描述符事件,可以注册、修改、删除
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
-
epfd:epoll_create生成的epoll专用的文件描述符
-
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; struct epoll_event { uint32_t event; epoll_data data; } events: EPOLLIN 读 EPOLLOUT 写 EPOLLERR 异常
epoll_wait
等待IO事件发生
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
-
epfd:epoll_create生成的epoll专用的文件描述符
-
events:用于回传待处理事件的数组(传出参数)
-
maxevents:告诉内核这个events的大小(events数组的大小肯定是有上限的)
-
timeout:超时时间
-
-1:永久阻塞
-
0:立即返回
-
>0:超时时间
-
代码示例
#include <ctype.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <ctype.h> #include <sys/epoll.h> int main(int argc, const char* argv[]) { if (argc < 2) { printf("eg: ./a.out port "); exit(1); } struct sockaddr_in serv_addr; socklen_t serv_len = sizeof(serv_addr); int port = atoi(argv[1]); int lfd = socket(AF_INET, SOCK_STREAM, 0); memset(&serv_addr, 0, serv_len); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(port); bind(lfd, (struct sockaddr*)&serv_addr, serv_len); listen(lfd, 36); printf("start accept........... "); struct sockaddr_in client_addr; socklen_t cli_len = sizeof(client_addr); //创建epoll树根节点 int epfd = epoll_create(2000); //初始化epoll树 struct epoll_evnet ev; ev.events = EPOLLIN; ev.data.fd = lfd; epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev); struct epoll_event all[2000]; while (1) { int ret = epoll_wait(epfd, all, sizeof(all)/sizeof(all[0]), -1); for (int i =0; i < ret; i++) { int fd = all[i].data.fd; //判断是否有新连接 if (fd == lfd) { //接收连接请求 int cfd = accept(lfd, (struct sockaddr*)&client_addr, &cli_len); if (cfd == -1) { perror("accept error"); exit(1); } struct epoll_event temp; temp.events = EPOLLIN; temp.data.fd = cfd; epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &temp); //打印客户端信息 char ip[64] = {0}; printf("new client ip: %s, port: %d ", inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)), ntohs(client_addr.sin_port)); } else { //处理已连接的客户端发送过来的数据 if (!all[i].events & EPOLLIN) { continue; } //读数据 char buf[1024] = {0}; int len = recv(fd, buf, sizeof(buf), 0); if (len == -1) { perror("recv error"); exit(1); } else if (len == 0) { printf("client disconnected "); //将fd从树上删除 ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); if (ret == -1) { perror("epoll-ctl del error"); exit(1); } close(fd); } else { printf("recv buf:%s ", buf); write(fd, buf, len); } } } }; close(lfd); return 0; }
参考资料
http://www.man7.org/linux/man-pages/man7/epoll.7.html