使用epoll在linux上开发高性能应用服务器 - Linux系统
概述
epoll是linux提供一种多路复用的技术,类似各个平台都支持的select,只是epoll在内核的实现做了 更多地优化,可以支持比select更多的文件描述符,当然也支持 socket这种网络的文件描述符。linux上 的大并发的接入服务器,目前的实现方式肯定都通过epoll实现。 epoll和线程 有很多开发人员用epoll的时候,会开多个线程来进行数据通信,比如一个线程专门accept(我个人早 些年在FreeBSD用kqueue的时候,由于对内部机制没有基本了解也这样搞),一个线程收发,或者接收和发 送都用各自独立的线程。 通常情况下,accept独立线程是没必要的,accept对于内核而言,就应用程序从内核的未完成的SYN队 列读取一点数据而已。具体参见 accept部分: TCP三次握手过程与对应的Berkeley Socket APIs的介绍 收发独立成两个线程也没有必要,因为大部分的应用服务器,通常情况下,启动一个线程收发数据, 最大数据的收发量瓶颈在于网卡,而不是CPU;像网游接入服务器配置一个KM的网卡,很少有游戏会申请 1G的带宽,那一台机器得有多少数据输入和输出。所以我们通信线程为epoll服务器就够了。 epoll的基本原理 为了让某些朋友能读得更连惯,我还是说一下epoll基本原理。 epoll外部表现和select是一样的。他提供READ, WRITE和ERROR等事件。 大致流程像下面这样: 1. 应用注册感兴趣的事件到内核; 2. 内核在某种条件下,将事件通知应用程序; 3. 应用程序收到事件后,根据事件类型做对应的逻辑处理。 原理部分我再说一下,不容易理解的地方,包括水平触发和边缘触发,WRITE事件的事件利用(这个可 以结合参考文献1的kqueue的WRITE事件,原理一致的)和修改事件的细节。 水平触发 READ事件,socket recv buff有数据,将一直向应用程序通知,直到buff为空。 WRITE事件,socket send buff从满的状态到可发送数据,将一直通知应用程序,直到buff满。 边缘触发 READ事件,socket recv buff有数据了,只通知应用一次,不管应用程序有没有调用read api,接下 来都不通知了。 WRITE事件,socket send buff从满的状态到可以发送数据,只通知一次。 上面这个解释不知道大家能否理解,也只能这样说了。有疑问的做一下试验。另外,这些细节的东西 ,前几年固定下来后,这几年做的项目,是直接用的,也就很少在涉及细节,是凭理解和记忆写下的文字 ,万一有错请指正^-^。 WRITE事件的利用 这个还一下不好描述。大概描述一下,详细看参考文献1。大致这样: 1. 逻辑层写数据到应用层的发送buff,向epoll注册一下WRITE事件; 2. 这时epoll会通知应用程序一个WRITE事件; 3. 在WRITE事件响应函数里,从应用层的发送buff读数据,然后用socket send api发送。 因为我在很多实际项目中,看到大家没有利用epoll的WRITE的事件来发数据,特意地说一下。大部分 的项目,是直接轮询应用程序的发送队列,我早期项目也是这么干的。
(编辑:佛山站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |