




已阅读5页,还剩15页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
select,poll,epoll三种通信模式的比较,主要介绍三种模式的基本内容,以及三种模式对比的优缺点,select为什么会出现,先看一下下面的这句代码:intiResult=recv(s,buffer,1024);这是用来接收数据的,在默认的阻塞模式下的套接字里,recv会阻塞在那里,直到套接字连接上有数据可读,把数据读到buffer里后recv函数才会返回,不然就会一直阻塞在那里。在单线程的程序里出现这种情况会导致主线程(单线程程序里只有一个默认的主线程)被阻塞,这样整个程序被锁死在这里,如果永远没数据发送过来,那么程序就会被永远锁死。这个问题可以用多线程解决,但是在有多个套接字连接的情况下,这不是一个好的选择,扩展性很差。再看代码:,intiResult=ioctlsocket(s,FIOBIO,(unsignedlong*)这一次recv的调用不管套接字连接上有没有数据可以接收都会马上返回。原因就在于我们用ioctlsocket把套接字设置为非阻塞模式了。不过你跟踪一下就会发现,在没有数据的情况下,recv确实是马上返回了,但是也返回了一个错误:WSAEWOULDBLOCK,意思就是请求的操作没有成功完成。看到这里很多人可能会说,那么就重复调用recv并检查返回值,直到成功为止,但是这样做效率很成问题,开销太大。select模型的出现就是为了解决上述问题。select模型的关键是使用一种有序的方式,对多个套接字进行统一管理与调度。,函数原型:intselect(intnfds,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,structtimeval*timeout);nfds:整型变量,他比所有的文件描述符集合中的最大值大1(为什么大1,因为文件描述符从0开始计数,这里代表数量吧)readfds:文件描述符监视文件集合中的任何文件是否有数据可读,可以被recv()、read()等进行读数据操作writefds:文件描述符监视文件集合中的任何文件是否有数据可写,可以被send()、write()等进行写数据操作exceptfds:监视文件集中是否发生错误timeout:设置所监视的文件集合中的事件没有发生时,最长的等待时间,关于fd_set的一些说明1.fd_set结构体fd_set是文件句柄的集合。FD_ZERO清空这个集合;FD_SET往这个集合里面加入一个文件句柄;FD_ISSET查看某一个文件句柄是否被设置了;fd_set是一组文件描述符(fd)的集合。由于fd_set类型的长度在不同平台上不同,因此应该用一组标准的宏定义来处理此类变量:fd_setset;FD_ZERO(/*判断fd是否处于可用状态是为true*/关于select函数的具体用法,这里就不再阐述,select函数的优缺点,优点:select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一。,缺点:有两个很致命的缺点,select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟使得大量TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。,poll()函数,intpoll(structpollfd*fds,nfds_tnfds,inttimeout);structpollfdintfd;/*文件描述符*/shortevents;/*请求的事件*/shortrevents;/*返回的事件*/events的值及含义POLLIN有数据到来,文件描述符可读POLLPRI有紧急数据到来POLLOUT文件可写POLLRDHUP流式套接字半关闭POLLERR错误发生POLLHUP关闭POLLNVAL非法请求POLLRDNORM与POLLIN相同(那还写出来)POLLRDBAND优先数据可读POLLWRNORM有POLLOUT相同(汗!)POLLWRBAND优先数据可写,poll函数优缺点:,优点(改进):poll相对于select改进了fdsetsize的限制,poll没有再使用fdset数组结构,反而使用了pollfd,这样用户可以自定义非常大的pollfd数组,这个pollfd数组在kernel中的表现形式是poll_list链表,这样就不存在了1024的限制了缺点:除此之外poll相比select无太大区别,最主要是因为pool与select一样,他们对应的内核函数都是sys_poll,所以随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟使得大量TCP连接处于非活跃状态也就是说,当文件描述符很大的情况下,poll的效率也是相当的慢,虽然它能增加描述符的数量,但是效率问题反而更严重了,对比select和poll,epoll具有以下这些优点:1.支持一个进程打开大数目的socket描述符(FD)select最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048。对于那些需要支持的上万连接数目的IM服务器来说显然太少了。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也不是一种完美的方案。不过epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat/proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。2.IO效率不随FD数目增加而线性下降传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,不过由于网络延时,任一时间只有部分的socket是活跃的,但是select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。但是epoll不存在这个问题,它只会对活跃的socket进行操作-这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有活跃的socket才会主动的去调用callback函数,其他idle状态socket则不会,在这点上,epoll实现了一个伪AIO,因为这时候推动力在os内核。在一些benchmark中,如果所有的socket基本上都是活跃的-比如一个高速LAN环境,epoll并不比select/poll有什么效率,相反,如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idleconnections模拟WAN环境,epoll的效率就远在select/poll之上了。,总的来说,select/poll的缺点:1.每次调用时要重复地从用户态读入参数。2.每次调用时要重复地扫描文件描述符。3.每次在调用开始时,要把当前进程放入各个文件描述符的等待队列。在调用结束后,又把进程从各个等待队列中删除。epoll的改进:在执行epoll_create和epoll_ctrl时,已经把用户态的信息保存到内核态了,所以之后即使反复地调用epoll_wait,也不会重复地拷贝参数,扫描文件描述符,反复地把当前进程放入/放出等待队列。这样就避免了以上的三个缺点。当然,支持一个进程打开大数目的socket描述符(FD)也是一个改进,以上都是网上对三种模式的剖析,我来说下我通过写程序后对于这三种模式的理解:(个人理解,如有错误,还望指正)无所select还是poll,它们的函数都是在一个while循环中,每次都会调用,通过对do_select和do_poll函数,可以知道,每次两个函数都会扫描整个文件描述符,所以,在文件描述符原来越多的情况下,效率自然就慢了下来再看epoll,它在循环外面创建epoll_create,然后添加事件epoll_ctl,完了后在循环体内就只有一个epoll_wait,就是说epoll在等,有文件描述符产生,就是直接连接这个函数,这样的话,就省去了遍历整个文件描述符,这样一来,效率自然就高了,epoll的使用,epoll有两种工作方式,分别问LT和ET水平触发(level-triggered,也被称为条件触发)LT:只要满足条件,就触发一个事件(只要有数据没有被获取,内核就不断通知你)边缘触发(edge-triggered)ET:每当状态变化时,触发一个事件,epoll,用到的数据结构:typedefunionepoll_datavoid*ptr;intfd;_uint32_tu32;_uint64_t64;epoll_data_t;structepoll_event_uint32tevents;epoll_data_tdata;,结构体epoll_event被用于注册感兴趣的事件和回传所发生待处理的事件,epoll_data联合体用来保存触发事件的某个文件描述符相关的数据epoll_eventevents表示感兴趣的事件和被触发的事件,可能的取值为:EPOLLIN:对应的文件描述符可以读EPOLLOUT:对应的文件描述符可以写EPOLLPRI:紧急数据EPOLLERR:文件描述符发生错误EPOLLHUP:文件描述符被挂断EPOLLET:文件描述符有事件发生,epoll的三个函数,epoll的接口非常简单,一共就三个函数:1.intepoll_create(intsize);创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。,2.intepoll_ctl(intepfd,intop,intfd,structepoll_event*event);epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。第一个参数是epoll_create()的返回值,第二个参数表示动作,用三个宏来表示:EPOLL_CTL_ADD:注册新的fd到epfd中;EPOLL_CTL_MOD:修改已经注册的fd的监听事件;EPOLL_CTL_DEL:从epfd中删除一个fd;第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事,structepoll_event结构如下:structepoll_event_uint32_tevents;/*Epollevents*/epoll_data_tdata;/*Userdatavariable*/;events可以是以下几个宏的集合:EPOLLIN:表示对应的文件描述符可以读(包括对端SOCKET正常关闭);EPOLLOUT:表示对应的文件描述符可以写;EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);EPOLLERR:表示对应的文件描述符发生错误;EPOLLHUP:表示对应的文件描述符被挂断;EPOLLET:将EPOLL设为边缘触发(EdgeTriggered)模式,这是相对于水平触发(LevelTriggered)来说的。EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里,3.intepoll_wait(intepfd,structepoll_event*events,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 合同范本之样板房买卖合同5篇
- 重大疾病保险保障体系解析
- 五金销售及维修承包合同4篇
- 新媒体数字项目绩效评估报告
- 室内设计模型介绍
- 现代简约软装设计
- 2025西安铁路工程职工大学辅导员考试试题及答案
- 2025辽宁师范高等专科学校辅导员考试试题及答案
- 2025益阳师范高等专科学校辅导员考试试题及答案
- 青海省交通工程监理有限公司招聘笔试题库2025
- 智慧海南总体方案(2020-2025年)
- 便携式小板凳设计方案
- DG-TJ 08-2122-2021 保温装饰复合板墙体保温系统应用技术标准
- SFR-SE-ARC-0031激光跟踪设置-作业指导书
- 录音棚、摄影棚、直播室设计方案
- 河北工业大学C++终极题库
- 安全生产隐患排查概述PPT课件
- CRCC认证目录
- 稻谷加工毕业设计日加工籼稻400吨免淘洗大米生产线设计
- 因式分解—完全平方公式
- 社会保险申请表
评论
0/150
提交评论