`
ci287ci
  • 浏览: 19638 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

linux服务器编程--EPOLL

 
阅读更多

linux服务器编程--EPOLL
2010年07月01日
  介绍epoll的文章大多都详细介绍了epoll模型和select/poll模型之间的比较,这里就不再详细列举,只总结一下我对这两个模型的看法:
  1.要监视的文件句柄非常多,而且每次完成操作的句柄非常少,使用epoll模型效率比select/poll模型要高许多;2.取决于文静句柄的响应速度,在LAN环境中这几个模型的效率差不多;WAN环境中epoll的效率最高;
  1.Linux2.6内核epoll介绍
  先介绍2本书《The Linux Networking Architecture--Design and Implementation of Network Protocols in the Linux Kernel》,以2.4内核讲解Linux TCP/IP实现,相当不错.作为一个现实世界中的实现,很多时候你必须作很多权衡,这时候参考一个久经考验的系统更有实际意义。举个例子,linux内核中sk_buff结构为了追求速度和安全,牺牲了部分内存,所以在发送TCP包的时候,无论应用层数据多大,sk_buff最小也有272的字节.其实对于socket应用层程序来说,另外一本书《UNIX Network Programming Volume 1》意义更大一点.2003年的时候,这本书出了最新的第3版本,不过主要还是修订第2版本。其中第6章《I/O Multiplexing》是最重要的。Stevens给出了网络IO的基本模型。在这里最重要的莫过于select模型和Asynchronous I/O模型.从理论上说,AIO似乎是最高效的,你的IO操作可以立即返回,然后等待os告诉你IO操作完成。但是一直以来,如何实现就没有一个完美的方案。最著名的windows完成端口实现的AIO,实际上也是内部用线程池实现的罢了,最后的结果是IO有个线程池,你应用也需要一个线程池...... 很多文档其实已经指出了这带来的线程context-switch带来的代价。在linux 平台上,关于网络AIO一直是改动最多的地方,2.4的年代就有很多AIO内核patch,最著名的应该算是SGI那个。但是一直到2.6内核发布,网络模块的AIO一直没有进入稳定内核版本(大部分都是使用用户线程模拟方法,在使用了NPTL的linux上面其实和windows的完成端口基本上差不多了)。2.6内核所支持的AIO特指磁盘的AIO---支持io_submit(),io_getevents()以及对Direct IO的支持(就是绕过VFS系统buffer直接写硬盘,对于流服务器在内存平稳性上有相当帮助)。
  所以,剩下的select模型基本上就是我们在linux上面的唯一选择,其实,如果加上no-block socket的配置,可以完成一个"伪"AIO的实现,只不过推动力在于你而不是os而已。不过传统的select/poll函数有着一些无法忍受的缺点,所以改进一直是2.4-2.5开发版本内核的任务,包括/dev/poll,realtime signal等等。最终,Davide Libenzi开发的epoll进入2.6内核成为正式的解决方案
  2、epoll的优点
  支持一个进程打开大数目的socket描述符(FD)
  select 最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048。对于那些需要支持的上万连接数目的IM服务器来说显然太少了。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的 Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也不是一种完美的方案。不过 epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。
  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,效率相比还有稍微的下降。但是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。
  3、epoll的使用方法   //epoll的接口非常简单,一共就三个函数: 1. int epoll_create(int size); 创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。 2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。第一个参数是epoll_create()的返回值,第二个参数表示动作,用三个宏来表示: EPOLL_CTL_ADD:注册新的fd到epfd中; EPOLL_CTL_MOD:修改已经注册的fd的监听事件; EPOLL_CTL_DEL:从epfd中删除一个fd; 第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下: struct epoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ }; events可以是以下几个宏的集合: EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭); EPOLLOUT:表示对应的文件描述符可以写; EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来); EPOLLERR:表示对应的文件描述符发生错误; EPOLLHUP:表示对应的文件描述符被挂断; EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。 EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里 3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); 等待事件的产生,类似于select()调用。参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。  
  首先通过create_epoll(int maxfds)来创建一个epoll的句柄,其中maxfds为你epoll所支持的最大句柄数。这个函数会返回一个新的epoll句柄,之后的所有操作将通过这个句柄来进行操作。在用完之后,记得用close()来关闭这个创建出来的epoll句柄。之后在你的网络主循环里面,每一帧的调用epoll_wait(int epfd, epoll_event events, int max events, int timeout)来查询所有的网络接口,看哪一个可以读,哪一个可以写了。基本的语法为:
  nfds = epoll_wait(kdpfd, events, maxevents, -1);
  其中kdpfd为用epoll_create创建之后的句柄,events是一个epoll_event*的指针,当epoll_wait这个函数操作成功之后,epoll_events里面将储存所有的读写事件。max_events是当前需要监听的所有socket句柄数。最后一个timeout是 epoll_wait的超时,为0的时候表示马上返回,为-1的时候表示一直等下去,直到有事件范围,为任意正整数的时候表示等这么长的时间,如果一直没有事件,则范围。一般如果网络主循环是单独的线程的话,可以用-1来等,这样可以保证一些效率,如果是和主逻辑在同一个线程的话,则可以用0来保证主循环的效率。
  //epoll_wait范围之后应该是一个循环,遍利所有的事件: for(n = 0; n 注册事件,最后启动网络监视线程。
  (d) 网络监视线程启动循环,epoll_wait()等待epoll事件发生。
  (e) 如果epoll事件表明有新的连接请求,则调用accept()函数,将用户socket描述符添加到epoll_data联合体,同时设定该描述符为非阻塞,并在epoll_event结构中设置要处理的事件类型为读和写,工作方式为epoll_ET.
  (f) 如果epoll事件表明socket描述符上有数据可读,则将该socket描述符加入可读队列,通知接收线程读入数据,并将接收到的数据放入到接收数据的链表中,经逻辑处理后,将反馈的数据包放入到发送数据链表中,等待由发送线程发送。
分享到:
评论

相关推荐

    Linux网络编程-网络基础-socket编程-高并发服务器.pdf

    【Linux网络编程-网络基础-socket编程-高并发服务器】 在深入探讨Linux下的网络编程之前,我们首先要理解网络通信的基础概念——协议。协议是数据传输和解释的规则,它确保了不同设备之间的通信能顺利进行。例如,...

    linux服务器大并发编程之epoll使用手册-epoll可实现5万socket tcp同时在线.zip

    linux服务器大并发编程之epoll使用手册-epoll可实现5万socket tcp同时在线.zip

    EPOLL-linux下select-poll的增强版

    在编程实践中,理解这些基础概念以及它们在不同场景下的应用非常重要,特别是对于编写高并发、高性能的服务器程序,EPOLL 的使用显得尤为关键。正确理解和使用 EPOLL 可以显著提升程序的效率和可靠性。

    socket网络编程-epoll-水平触发和边缘触发源码

    socket网络编程-epoll-水平触发和边缘触发源码。 (1)I/O多路复用技术用于监控多个TCP连接上的数据收发,而epoll就是一种在Linux上使用的I/O多路复用并支持高并发的典型技术。传统的select、poll也是I/O多路复用...

    linux-xia-epoll-socket.rar_epoll_epoll socket_socket_windows soc

    在Linux操作系统中,`epoll`是一个用于处理大量并发I/O事件的高效机制,尤其适用于网络编程中的套接字(socket)操作。`epoll`是`poll`和`select`模型的升级版,旨在解决高并发场景下的性能瓶颈问题。在本资料包中,...

    linux网络编程-源代码.rar

    《Linux网络编程》一书是IT领域中关于操作系统与网络通信的经典教材,它深入探讨了在Linux环境下如何进行网络编程,涵盖了从低级socket接口到高级应用层协议的实现。这个压缩包“linux网络编程-源代码.rar”包含了该...

    Linux网络编程-文字版.pdf

    Linux网络编程是计算机网络领域的一项基础而核心的技术。它涉及到操作系统内核级别的通信机制,尤其是在Linux这样的类Unix系统上,网络编程的基本单元是套接字(Socket)。下面将从几个方面详细解析Linux网络编程的...

    Linux高性能服务器编程,linux高性能服务器编程 pdf,C,C++

    3. **异步I/O模型**:深入理解各种I/O模型,如阻塞I/O、非阻塞I/O、IO复用(select、poll、epoll)、信号驱动I/O和异步I/O,以及它们在服务器编程中的应用场景和优缺点。 4. **网络编程**:详细讲解TCP/IP协议栈,...

    Linux网络编程-网络基础-socket编程-高并发服务器.doc

    Linux网络编程涉及网络基础知识,尤其是Socket编程和高并发服务器的实现。网络协议是通信的规则,比如文件传输协议FTP,它的基本流程包括三次数据传输:文件名、文件大小和文件内容。随着协议的发展和标准化,形成了...

    linux 编程教程 -- linux下编程入门

    Linux编程教程——Linux下编程入门 在Linux操作系统中进行编程是一项重要的技能,尤其对于系统级开发者和软件工程师来说。Linux提供了丰富的开发环境和工具,支持多种编程语言,如C、C++、Python、Java等。本教程将...

    0.2-chat-epoll.zip

    标题中的"0.2-chat-epoll.zip"表明这是一个关于聊天程序的项目,版本号为0.2,它使用了Linux下的epoll技术。epoll是Linux内核提供的一种高效I/O事件通知机制,尤其适合多路复用的高并发场景,如聊天应用。这个项目...

    Linux网络编程 - 副本(1).rar

    在IT行业中,Linux网络编程是构建高性能服务器和网络应用程序的核心技术。这个主题涵盖了广泛的理论和实践知识,包括网络协议、套接字编程、多线程、并发处理、系统调用等。下面,我们将深入探讨"Linux网络编程"这一...

    linux epoll多线程编程 例子

    总结来说,Linux的epoll多线程编程能够有效地提升高并发场景下的系统性能,通过结合线程池,可以更好地管理和调度资源,降低系统开销。正确理解和运用这些技术,对于开发高效、稳定的服务器程序至关重要。

    Linux高性能服务器编程电子版

    《Linux高性能服务器编程》这本书是针对那些希望深入理解如何在Linux环境下构建高效、稳定服务器的开发者和运维人员的宝贵资源。书中的内容涵盖了广泛的Linux系统编程和服务器优化技术,旨在帮助读者提升系统的性能...

    linux网络编程-源代码&课件.zip

    此外,Linux网络编程中的一个重要概念是I/O模型,包括阻塞I/O、非阻塞I/O、I/O复用(select、poll、epoll)、信号驱动I/O和异步I/O。这些模型在处理大量并发连接时尤其关键,因为它们决定了程序如何高效地管理等待I/...

    python-epoll-examples

    Python中的epoll是用于处理高并发I/O操作的高效机制,尤其在服务器编程中非常关键。它是Linux内核提供的一个接口,主要用于解决多路复用I/O问题,比如网络编程中的socket通信。在这个"python-epoll-examples"压缩包...

Global site tag (gtag.js) - Google Analytics