I/O多路复用之-epoll
来源:互联网 发布:老外中国快递知乎 编辑:程序博客网 时间:2024/05/22 08:01
I/O多路复用之-epoll
之前的select和poll实现I/O多路复用都用一个很大的弊端,那就是在轮询的时候需要轮询对象集合中的所用文件描述符,如果对象集合中有用的文件描述符很少,那就会做很多无用的轮询,相对浪费资源。epoll函数就可以解决这个问题。
epoll与select、poll不同,首先,不用每次调用都向内核拷贝事件描述信息,在第一次调用后,事件信息就会与对应的epoll描述符关联起来。另外epoll不是通过轮询,而是通过在等待的描述符上注册回调函数,当事件发生时,回调函数负责把发生的事件存储在就绪事件链表中,最后写到用户空间。epoll返回后,该参数指向的缓冲区中即为发生的事件,对缓冲区中每个元素进行处理即可,而不需要像poll、select那样进行轮询检查。
epoll通过epoll_create创建一个用于epoll轮询的描述符,通过epoll_ctl添加/修改/删除事件,epoll_wait检查事件,epoll_wait的第二个参数用于存放结果。
1、创建文件描述符
intepoll_create(int size);/*早期的size参数为创建的描述符允许的最大值,2001版本后的取消了该限制,为了接口兼容,仍然设置该参数,但该参数实为无用参数。*/
2、管理对象及事件
typedefunion epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
}epoll_data_t;
structepoll_event {
uint32_t events; /* 监测事件*/
epoll_data_t data; /* 附加数据,常用于存储文件描述符*/
};
EPOLLIN- 读事件
EPOLLOUT-写事件
3、通知内核
intepoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
intepfd :epoll文件描述符
int op :命令码
EPOLL_CTL_ADD:向epoll添加对象及事件
EPOLL_CTL_MOD:修改epoll已有对象及事件
EPOLL_CTL_DEL:删除epoll已有对象及事件
int fd :监测对象(等谁)
struct epoll_event *event
4、等事件发生并读结果
int epoll_wait(int epfd, struct epoll_event*events,
int maxevents, inttimeout);
功能:等事件发生并读结果
参数:
int epfd - epoll文件描述符
struct epoll_event *event
- 保存事件发生事件的缓存首地址
int maxevents - 想保存的数量
int timeout - 超时值(单位:毫秒)
时间值0 :非阻塞
合理的时间值 : 时间到时不满足即超时
-1 : 阻塞(-1的补码即是最大的整数,等待时间最长即为阻塞)
返回值:
失败:-1
超时:0
成功:实际发生的数量
5、轮询
for(inti = 0; i < num; i++){ /*num为epoll_wait()的返回值*/
if(EPOLLIN & events[i].events){
读
read();
}
if(EPOLLOUT & events[i].events){
写
write();
}
}
利用epoll()构建一个模拟并发服务器(实现多连接):
#include <stdio.h>#include <string.h>#include <sys/types.h> #include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <sys/epoll.h>#define EMAX 1024#define MAX 1024int init_server(const char *ipstr, unsigned short port, int backlog){int s = socket(AF_INET, SOCK_STREAM, 0);if(0 > s){perror("socket");return -1;}struct sockaddr_in addr = {.sin_family = AF_INET,.sin_port = htons(port),.sin_addr = {.s_addr = (NULL == ipstr ? INADDR_ANY : inet_addr(ipstr)),},};memset(addr.sin_zero, 0, sizeof(addr.sin_zero));socklen_t len = sizeof(addr);if(0 > bind(s, (struct sockaddr *)&addr, len)){perror("bind");return -1;}if(0 > listen(s, backlog)){perror("listen");return -1;}return s;}int add_event(int efd, int fd, int event){struct epoll_event evt = {.events = event,.data = {.fd = fd,},};return epoll_ctl(efd, EPOLL_CTL_ADD, fd, &evt);}int del_event(int efd, int fd){return epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL);}int main(){int s = init_server(NULL, 9999, 1);if(0 > s){return -1;}printf("Wait for new comming ...\n");int efd = epoll_create(1);if(0 > efd){perror("epoll_create");return -1;}if(0 > add_event(efd, s, EPOLLIN)){perror("add_event");return -1;}struct epoll_event evts[EMAX];while(1){memset(evts, 0, sizeof(evts));int ret = epoll_wait(efd, evts, EMAX, 1000);if(0 > ret){perror("select");break;}else if(0 == ret){printf("\tTimeout.\n");continue;}for(int i = 0; i < ret; i++){if(s == evts[i].data.fd){struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));socklen_t len = sizeof(addr);int rws = accept(s, (struct sockaddr*)&addr, &len);if(0 > rws){perror("accept");return -1;}printf("a nen comming [%s:%u] \n", \ inet_ntoa(addr.sin_addr), \ ntohs(addr.sin_port));if(0 > add_event(efd, rws, EPOLLIN)){perror("add_event");close(rws);}}else{char buf[MAX];memset(buf, 0, MAX);int len = read(evts[i].data.fd, buf, MAX-1);if(0 >= len){printf("read [%d] fail .\n", evts[i].data.fd);if(0 > del_event(efd, evts[i].data.fd)){perror("del_event");}close(evts[i].data.fd);}else{printf("sock[%d], RECV[%dbytes]:%s\n", evts[i].data.fd, len, buf);}}}}close(s);}
- I/O多路复用之epoll
- I/O多路复用之-epoll
- I/O多路复用之epoll
- I/O多路复用之epoll
- I/O多路复用之epoll
- epoll I/O 多路复用
- 多路复用I/O--epoll
- I/O多路复用技术之 - epoll
- I/O 多路复用之 Select & Epoll
- I/O多路复用之select/poll/epoll
- I/O多路复用之 epoll 系统调用
- Linux--高级I/O多路复用之epoll
- I/O多路复用之epoll学习总结
- I/O多路复用之epoll服务器
- Epoll编程-I/O多路复用
- epoll实现I/O多路复用
- epoll编程-I/O多路复用
- Linux I/O多路复用之select,poll与epoll区别
- Eclipse插件安装
- Lua学习笔记--环境配置&Hello World
- 贪心算法New Year BonusGrant
- 供应商信息一览
- Tomcat Web
- I/O多路复用之-epoll
- [leetcode-138]Copy List with Random Pointer(java)
- 常用的Javascript设计模式
- 111111111111111
- 九度 Online Judge 算法 刷题 题目1095:2的幂次方
- Tiled Map Editor(瓦片地图编辑器)的Java和QT版本区别
- Gym 100625D 已知一条边追踪游人-最短路径-(两次dijkstra算法)
- 哈希、HashMap原理及源码、Hash的一些应用面试题
- 在程序中提交XMLP报表