`
russelltao
  • 浏览: 158355 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

linux下epoll如何实现高效处理百万句柄的

 
阅读更多

开发高性能网络程序时,windows开发者们言必称iocp,linux开发者们则言必称epoll。大家都明白epoll是一种IO多路复用技术,可以非常高效的处理数以百万计的socket句柄,比起以前的select和poll效率高大发了。我们用起epoll来都感觉挺爽,确实快,那么,它到底为什么可以高速处理这么多并发连接呢?


先简单回顾下如何使用C库封装的3个epoll系统调用吧。

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);

使用起来很清晰,首先要调用epoll_create建立一个epoll对象。参数size是内核保证能够正确处理的最大句柄数,多于这个最大数时内核可不保证效果。

epoll_ctl可以操作上面建立的epoll,例如,将刚建立的socket加入到epoll中让其监控,或者把 epoll正在监控的某个socket句柄移出epoll,不再监控它等等。

epoll_wait在调用时,在给定的timeout时间内,当在监控的所有句柄中有事件发生时,就返回用户态的进程。


从上面的调用方式就可以看到epoll比select/poll的优越之处:因为后者每次调用时都要传递你所要监控的所有socket给select/poll系统调用,这意味着需要将用户态的socket列表copy到内核态,如果以万计的句柄会导致每次都要copy几十几百KB的内存到内核态,非常低效。而我们调用epoll_wait时就相当于以往调用select/poll,但是这时却不用传递socket句柄给内核,因为内核已经在epoll_ctl中拿到了要监控的句柄列表。


所以,实际上在你调用epoll_create后,内核就已经在内核态开始准备帮你存储要监控的句柄了,每次调用epoll_ctl只是在往内核的数据结构里塞入新的socket句柄。


在内核里,一切皆文件。所以,epoll向内核注册了一个文件系统,用于存储上述的被监控socket。当你调用epoll_create时,就会在这个虚拟的epoll文件系统里创建一个file结点。当然这个file不是普通文件,它只服务于epoll。


epoll在被内核初始化时(操作系统启动),同时会开辟出epoll自己的内核高速cache区,用于安置每一个我们想监控的socket,这些socket会以红黑树的形式保存在内核cache里,以支持快速的查找、插入、删除。这个内核高速cache区,就是建立连续的物理内存页,然后在之上建立slab层,简单的说,就是物理上分配好你想要的size的内存对象,每次使用时都是使用空闲的已分配好的对象。

static int __init eventpoll_init(void)
{
	... ...

	/* Allocates slab cache used to allocate "struct epitem" items */
	epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem),
			0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC,
			NULL, NULL);

	/* Allocates slab cache used to allocate "struct eppoll_entry" */
	pwq_cache = kmem_cache_create("eventpoll_pwq",
			sizeof(struct eppoll_entry), 0,
			EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);

 ... ...


epoll的高效就在于,当我们调用epoll_ctl往里塞入百万个句柄时,epoll_wait仍然可以飞快的返回,并有效的将发生事件的句柄给我们用户。这是由于我们在调用epoll_create时,内核除了帮我们在epoll文件系统里建了个file结点,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket外,还会再建立一个list链表,用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表里有没有数据即可。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。所以,epoll_wait非常高效。


而且,通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已,如何能不高效?!


那么,这个准备就绪list链表是怎么维护的呢?当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。所以,当一个socket上有数据到了,内核在把网卡上的数据copy到内核中后就来把socket插入到准备就绪链表里了。


如此,一颗红黑树,一张准备就绪句柄链表,少量的内核cache,就帮我们解决了大并发下的socket处理问题。执行epoll_create时,创建了红黑树和就绪链表,执行epoll_ctl时,如果增加socket句柄,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树干上,然后向内核注册回调函数,用于当中断事件来临时向准备就绪链表中插入数据。执行epoll_wait时立刻返回准备就绪链表里的数据即可。


最后看看epoll独有的两种模式LT和ET。无论是LT和ET模式,都适用于以上所说的流程。区别是,LT模式下,只要一个句柄上的事件一次没有处理完,会在以后调用epoll_wait时次次返回这个句柄,而ET模式仅在第一次返回。


这件事怎么做到的呢?当一个socket句柄上有事件时,内核会把该句柄插入上面所说的准备就绪list链表,这时我们调用epoll_wait,会把准备就绪的socket拷贝到用户态内存,然后清空准备就绪list链表,最后,epoll_wait干了件事,就是检查这些socket,如果不是ET模式(就是LT模式的句柄了),并且这些socket上确实有未处理的事件时,又把该句柄放回到刚刚清空的准备就绪链表了。所以,非ET的句柄,只要它上面还有事件,epoll_wait每次都会返回。而ET模式的句柄,除非有新中断到,即使socket上的事件没有处理完,也是不会次次从epoll_wait返回的。


分享到:
评论

相关推荐

    linux 下 通过epoll实现tcp服务器

    总之,`epoll`是Linux下实现高性能TCP服务器的关键技术,通过合理利用它可以构建出高效、稳定的网络服务程序。结合提供的源代码,我们可以深入理解`epoll`的工作机制和TCP服务器的实现细节,为实际开发提供参考。

    linux下epoll示例程序

    在Linux操作系统中,`...综上所述,`EpollServer.cpp`和`EpollClient.cpp`的示例程序展示了如何使用`epoll`在Linux下实现一个多人聊天应用,通过高效的I/O多路复用技术,实现了服务器端与多个客户端之间的实时通信。

    linux epoll 的实现

    Linux下的epoll是一种高效、可扩展的I/O多路复用技术,主要用于处理大量并发连接。它是基于事件驱动的I/O模型,适用于高并发服务器,如Web服务器、数据库服务器等。在epoll中,系统会监控一组文件描述符,当这些文件...

    Linux环境下Epoll系统调用实现web服务器并发工作

    在Linux操作系统中,为了处理高并发的网络连接,开发者通常会采用I/O多路复用技术,其中Epoll(Event Poll)是Linux提供的一种高效、可扩展的机制。本篇文章将详细探讨如何在Linux环境下利用Epoll系统调用来实现一个...

    Linux下使用EPoll+队列+多线程的C++实现

    在这个“Linux下使用EPoll+队列+多线程的C++实现”项目中,开发者使用了`epoll`来监听并管理TCP服务器的连接。`epoll`的工作流程大致如下: 1. **创建epoll句柄**:首先,通过`epoll_create()`函数创建一个epoll...

    linux_epoll

    Linux下的`epoll`是I/O多路复用技术的一种高效实现,主要用于高并发的网络编程。`epoll`在传统的`select`和`poll`基础上进行了改进,提供了更好的性能和可扩展性。本知识讲解将围绕`epoll`的工作原理、如何封装`...

    tcp.zip_epoll_epoll client_epoll server_linux tcp epoll_tcp epol

    总结来说,这个项目涉及到了Linux系统下的高性能TCP服务器和客户端编程,使用了C++的面向对象设计,核心在于利用epoll进行I/O多路复用,从而实现高效、并发的网络通信。通过分析压缩包内的源代码,可以深入理解epoll...

    linux epoll服务器

    总结来说,这个Linux下的epoll TCP服务器示例涵盖了网络编程的基础要素,通过epoll机制实现了高效的事件驱动模型,适合学习和理解I/O多路复用技术在实际应用中的使用。同时,`Client.cpp`文件的存在使我们可以自测...

    linux_epoll模型

    相比之下,`epoll`是Linux 2.6内核引入的一种优化过的I/O多路复用机制,特别是针对大规模句柄的情况。`epoll`的主要优点包括: 1. **无限制的句柄数**:`epoll`不再受到`FD_SETSIZE`的限制,可以处理成千上万的并发...

    epoll函数实现多客户端并发

    `epoll`函数就是Linux系统提供的一种高效、可扩展的I/O多路复用技术,它在C语言环境下被广泛使用。本文将深入探讨`epoll`如何帮助我们实现多客户端并发,并分析其在C语言网络编程中的应用。 首先,让我们理解什么是...

    epoll 使用golang实现

    在IT领域,`epoll`是一种高效的I/O事件通知机制,尤其在处理大量并发连接时,它是Linux系统下的首选方案。`epoll`利用内核与用户空间的共享数据结构来减少上下文切换,提高了系统在高并发环境下的性能。本篇文章将...

    linux epoll用法小结

    Linux中的epoll是一种高效、可扩展的I/O多路复用技术,主要用于处理大量并发连接。epoll在处理大量打开文件描述符时,其性能优势显著优于传统的select和poll。 一、epoll接口 1. `epoll_create(int size)`: 这个...

    epoll学习资料

    深入理解Epoll的内部实现,可以研究`linuxepoll.tar.gz`和`linux epoll源码,支持大型服务器,适合高手研究.rar`这两个源码文件。这将帮助你了解Epoll在内核中的数据结构、事件分发机制以及如何优化性能。 **学习...

    epoll_udp服务器

    【epoll_udp服务器】是一种在Linux操作系统环境下,利用epoll机制构建的UDP(User Datagram Protocol)服务器,旨在高效地处理大量的并发连接并实现同时收发数据。UDP是一种无连接、不可靠的传输协议,适用于对实时...

    Linux socket编程探讨一(使用epoll处理海量连接).doc

    总之,epoll是Linux下处理海量连接的利器,通过其高效的事件驱动机制,能够有效地管理大量并发连接,实现高性能的网络服务。对于需要处理高并发场景的服务器开发人员来说,理解和掌握epoll的使用是必备技能。

    Windows完成端口与Linuxepoll技术简介.docx

    【Windows完成端口技术】 ...在Windows环境下,完成端口是首选,而在Linux中,epoll是现代服务器设计的标准选择。无论在哪个平台,理解和熟练使用这些技术对于编写高性能的网络服务器程序至关重要。

    windows下的epoll库源码

    在Linux操作系统中,epoll是一个高效且强大的I/O事件通知机制,常用于处理高并发网络服务。然而,Windows操作系统并没有原生支持epoll。为了在Windows环境下利用epoll的优势,开发者通常需要进行模拟实现。本压缩包...

    epoll模型设计海量级连接服务器

    在Linux系统中,`epoll`是用于处理大量并发连接的一种高效I/O多路复用技术,特别适合构建海量级连接服务器。相比传统的`select`和`poll`,`epoll`具有显著的优势,比如更高的可扩展性和更好的性能。本文将深入探讨`...

Global site tag (gtag.js) - Google Analytics