I/O 多路复用之 Select & Epoll
来源:互联网 发布:js调用微信分享sdk 编辑:程序博客网 时间:2024/05/22 17:31
本文将简要介绍 select 、epoll 接口,并从接口的设计、调用方式分析两者的差异,最后总结两者功能的差异。当然,为什么么会有这些差异还得去研究相关接口的内核实现细节。
1. Select
int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述副就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。当select函数返回后,可以 通过遍历fdset,来找到就绪的描述符。
select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。select的一 个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但 是这样也会造成效率的降低。
2. Epoll
epoll 使用起来也很清晰,
- 首先调用
epoll_create
建立一个epoll 对象,返回文件 fd epoll_ctl
可以操作上面建立的 epoll 对象进行,增添需要被监听新建立的 socket ,或从监听列表中删除某个 socket- 向
epoll_wait
函数传递一个struct epoll_event
结构参数,当在监控的所有句柄中有事件发生时,就返回数据已经准备就绪的 socket 文件描述符的数量 - 利用返回得到的准备就绪socket 的
num
(数量)轮询上面得到的struct epoll_event
, 根据描述符的类型和事件类型分别进行处理
从上面的调用方式就可以看到epoll比select/poll的优越之处:epoll 只对活跃的 socket 进行事件处理,并且通过 add、delete 的方式来增减 socket,省去了不必要的重复拷贝。
epoll_wait范围之后应该是一个循环,遍利所有的事件。
几乎所有的epoll程序都使用下面的框架:
for( ; ; ) { nfds = epoll_wait(epfd,events,20,500); for(i=0;i<nfds;++i) { if(events[i].data.fd==listenfd) //有新的连接 { connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen); //accept这个连接 ev.data.fd=connfd; ev.events=EPOLLIN|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); //将新的fd添加到epoll的监听队列中 } else if( events[i].events&EPOLLIN ) //接收到数据,读socket { n = read(sockfd, line, MAXLINE)) < 0 //读 ev.data.ptr = md; //md为自定义类型,添加数据 ev.events=EPOLLOUT|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);//修改标识符,等待下一个循环时发送数据,异步处理的精髓 } else if(events[i].events&EPOLLOUT) //有数据待发送,写socket { struct myepoll_data* md = (myepoll_data*)events[i].data.ptr; //取数据 sockfd = md->fd; send( sockfd, md->ptr, strlen((char*)md->ptr), 0 ); //发送数据 ev.data.fd=sockfd; ev.events=EPOLLIN|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); //修改标识符,等待下一个循环时接收数据 } else { //其他的处理 } } }
3. Different
从 select 的调用方式就可以看出,每次调用都要传递需要监控的所有 FD_SET ,这意味着需要将用户态的描述符集 copy 到内核。而且 select 只是在有事件发生时才被唤醒,并没有给出哪些文件描述符是准备就绪的,必须得通过一次 O(n) 的线性扫描。
所以 select 有如下几点缺陷:
- 每次调用 select 都需要把fd集合从用户态拷贝到内核态
- 拷贝结束后 select 都需要在内核遍历传递进来的所有fd
- select支持的文件描述符数量太小了,默认是1024
epoll 能解决上面三点缺陷
- 省去不必要的重复拷贝:epoll 通过内核与用户空间mmap同一块内存,保证了每个fd在整个过程中只会拷贝一次
- 效率:epoll 只会对”活跃”的socket进行操作—这是因为在内核中 epoll 是根据每个fd上面的 callback 函数实现的。只有”活跃”的socket才会主动的去调用 callback函数,其他idle状态socket则不会
- epoll 没有最大文件符限制,它所支持的FD上限是最大可以打开文件的数目
4. Reference
Linux IO模式及 select、poll、epoll详解
IO多路复用之epoll总结
epoll 详解
- I/O 多路复用之 Select & Epoll
- I/O多路复用之select/poll/epoll
- Linux I/O多路复用之select,poll与epoll区别
- Linux I/O多路复用之select,poll与epoll区别
- I/O多路复用之select,poll和epoll
- 【网络】高级I/O多路复用之select、poll和epoll
- I/O 多路复用之select、poll、epoll详解
- I/O多路复用之比较select&poll&epoll
- I/O多路复用之epoll
- I/O多路复用之-epoll
- I/O多路复用之epoll
- I/O多路复用之epoll
- I/O多路复用之epoll
- 浅析I/O多路复用:select、poll、epoll
- I/O多路复用---select、poll、epoll
- I/O多路复用(select、poll、epoll)
- I/O多路复用:select poll epoll
- I/O多路复用之select
- C语言&取址符、*寻址符(六)
- 中文排序
- Gzip解压缩、DES加密解密
- iOS中的预编译指令的初步探究
- WEB服务器、应用程序服务器、HTTP服务器区别
- I/O 多路复用之 Select & Epoll
- 如何使用Android Studio把自己的Android library分享到jCenter和Maven Central
- 屏幕适配 dp dpi px
- android graphic(11)—底层初始化displays
- 【信息安全】第一章 密码破解
- 下拉菜单被挡住问题
- 同态滤波
- XListView使用
- Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition