最好的参考资料:
1.师从互联网。
2.man 7 epoll
3.http://bbs.chinaunix.net/thread-1740209-1-1.html
4.http://hi.baidu.com/firobd/blog/item/dcb4f251530d341d0cf3e3ee.html
5.http://www.cnblogs.com/dubingsky/archive/2009/07/22/1528695.html
6.http://bbs.chinaunix.net/thread-1740209-2-1.html
7.http://www.cppblog.com/converse/archive/2008/04/29/48482.html
第一条:概述
简单说来 epoll 就是Linux内核解决大量的用户并发地连接到服务器上,而为程序员提供的开发大规模并发网络程序的一种I/O 多路复用技术。epoll是Linux下多路复用IO接口select/poll的增强版本,本质上仍是I/O多路复用技术,所以他没什么好怕的,但是epoll能力却非常强悍的。你会见到如此少的代码却能轻松的搞定如何接受大量用户连接的问题,非常厉害。
最早你可你在Kernel2.5.44中见到epoll的系统调用,2.6内核时被正式引进到glibc2.3.2中。epoll是linux特有的机制 类似与BSD的Kqueue和Solaris的/dev/poll。
第二条:Linux并发网络编程模型
(0)Apache 模型,简称 PPC ( Process Per Connection ,):为每个连接分配一个进程。主机分配给每个连接的时间和空间上代价较大,并且随着连接的增多,大量进程间切换开销也增长了。很难应对大量的客户并发连接。
(1) TPC 模型( Thread Per Connection ):每个连接一个线程。和PCC类似。
(2) select 模型:I/O多路复用技术。
(2.1)每个连接对应一个描述。select模型受限于 FD_SETSIZE即进程最大打开的描述符数linux2.6.35为1024,实际上linux每个进程所能打开描数字的个数仅受限于内存大小,然而在设计select的系统调用时,却是参考FD_SETSIZE的值。可通过重新编译内核更改此值,但不能根治此问题,对于百万级的用户连接请求 即便增加相应 进程数, 仍显得杯水车薪呀。
(2.2)select每次都会扫描一个文件描述符的集合,这个集合的大小是作为select第一个参数传入的值。但是每个进程所能打开文件描述符若是增加了 ,扫描的效率也将减小。
(2.3)内核到用户空间,采用内存复制传递文件描述上发生的信息。
(3)poll 模型:I/O多路复用技术。poll模型将不会受限于FD_SETSIZE,因为内核所扫描的文件 描述符集合的大小是由用户指定的,即poll的第二个参数。但仍有扫描效率和内存拷贝问题。
(4)pselect模型:I/O多路复用技术。同select。
(5)epoll模型:
(5.1)无文件描述字大小限制仅与内存大小相关
(5.2)epoll返回时已经明确的知道哪个socket fd发生了什么事件,不用像select那样再一个个比对。
(5.3)内核到用户空间采用共享内存方式,传递消息。
第三条:epoll API
#include <sys/epoll.h>//epoll机制相关的所需的API和数据类型都在这个头文件中
(0)int epoll_create (int size) ;
(0.1)函数返回一个epoll专用的描述符epfd,epfd引用了一个新的epoll机制例程(instance.)。
(0.2)参数size是这个epoll专用描述符epfd所关联的socketfd的最大个数。man手册指出:The size is not the maximum size of the backing store but just a hint to the kernel about how to dimension internal structures. (Nowadays, size is ignored; see NOTES below.)从2,6.8内核就不使用这个参数,而是内核动态分配所需的数据结构。
(0.3)当我们不再需要epfd时,一定要调用close关闭他。当epfd被关闭时,kernel销毁所引用的instance和释放相关资源。
(1) int epoll_create1(int flags);
(1.1)正如man手册所指出的epoll_create的参数size,其实已经被抛弃了,毫无用处。epoll_create1和epoll_create功效一样,而且还添加了一个flags参数,其值如下:
enum {
EPOLL_CLOEXEC = 02000000,//在新建的epfd上设置FD_CLOEXEC。
EPOLL_NONBLOCK = 04000 //新建的epfd设置为非阻塞。
};
(2)int epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event) ;//设置epfd关联的一个socketfd
(2.1)参数epfd的值设置为epoll_create返回的epoll专用描述符。
(2.2)参数op值如下:
#define EPOLL_CTL_ADD 1 /* Add a file decriptor to the interface. */关联一个socketfd到epfd
#define EPOLL_CTL_DEL 2 /* Remove a file decriptor from the interface. */删除一个epfd已经关联的socketfd
#define EPOLL_CTL_MOD 3 /* Change file decriptor epoll_event structure. */更新一个epfd已经关联的socketfd
(2.3)参数fd设置为我们要操作的socketfd
(2.4) 参数event具体如何设置socketfd,其值如下:
typedef union epoll_data {//注意这是union结构~~~
void *ptr;
int fd;//一般都用这个成员
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {//呵呵,这个数据结构就是epoll为什么如此高效的原因。
uint32_t events; /* Epoll events *///对应的时间
epoll_data_t data; /* User data variable *///此值一般是关心的socketfd
};
成员events对应的值如下,他表示相应的描述符发生的事件或状态:
enum EPOLL_EVENTS
{
EPOLLIN = 0x001,//可读
EPOLLPRI = 0x002,//有紧急数据可读,比如带外数据
EPOLLOUT = 0x004,//可写
EPOLLRDNORM = 0x040,
EPOLLRDBAND = 0x080,
EPOLLWRNORM = 0x100,
EPOLLWRBAND = 0x200,
EPOLLMSG = 0x400,
EPOLLERR = 0x008,//出错
EPOLLHUP = 0x010,//挂断
EPOLLRDHUP = 0x2000,//连接断开,或处于半关闭状态(前提是对应的流socket,就是支持连接的socket)。man手册中的说明:(since Linux 2.6.17) Stream socket peer closed connection, or shut down writing half of connection. (This flag is especially useful for writing simple code to detect peer shutdown when using Edge Triggered monitoring.)
EPOLLONESHOT = (1 << 30),/*默认监听一个socketfd之后并不把它从epfd关联的socketfd集合中删除,只清空socketfd对应的事件成员的值一次事件。EPOLLONESHOT表示设置socketfd为监听一次事件。当监听完这次事件之后,从epfd关联的socketfd集合中删除监听的socketfd,如果还需要继续监听这个socketfd的话,需要再次把这个socketfd加入到epfd关联的socketfd集合(队列)里 */
EPOLLET = (1 << 31)// 将epfd设为边缘触发(Edge Triggered)模式,默认epfd是电平触发(Level Triggered)。 下文细述。
};
(3)int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask);//想想pselect
(3.1)参数events指向一个struct epoll_event类型的数组,内核用他来装载发生的事件传送给用户。
(3.2)参数maxevents指明数组的大小。
(3.3)参数timeout:超时时间。
(3.4)参数sigmask:信号屏蔽集。epoll_pwait等价如下:
sigset_t origmask;
sigprocmask(SIG_SETMASK, &sigmask, &origmask);
ready = epoll_wait(epfd, &events, maxevents, timeout);
sigprocmask(SIG_SETMASK, &origmask, NULL);
epoll_wait等待epfd关联的socketfd上发生事件,如果发生了内核把发生事件的socketfd和事件类型放到events数组当中(就是这个小小的细节就决定了epoll强悍的性能,因为他不需要像select再轮询所有的socketfd集合,去确定哪个socketfd 要去处理。同时内核也会将epfd关联的socketfd的struct evpoll_event结构的事件类型成员(events)清空(不是epoll_wait函数的第二个参数events,要严重区分),所以如果下次你还要关注这个socketfd就需要用epoll_ctl的EPOLL_CTL_MOD(不是EPOLL_CTL_ADD,socketfd并未清空,只是事件类型清空)命令来重新设置我们关心socketfd的事件类型。重新设置这一步非常重要!!!
第四条:epoll工作模式
epoll有两种工作方式
ET:Edge Triggered,边缘触发。仅当状态发生变化时才会通知,epoll_wait返回。换句话,就是对于一个事件,只通知一次。且只支持非阻塞的socket。
LT:Level Triggered,电平触发(默认工作方式)。类似select/poll,只要还有没有处理的事件就会一直通知,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll.支持阻塞和不阻塞的socket。
第五条:FAQ
来自互联网,链接见上面
1、单个epoll并不能解决所有问题,特别是你的每个操作都比较费时的时候,因为epoll是串行处理的。 所以你有还是必要建立线程池来发挥更大的效能。
2、如果fd被注册到两个epoll中时,如果有时间发生则两个epoll都会触发事件。
3、如果注册到epoll中的fd被关闭,则其会自动被清除出epoll监听列表。
4、如果多个事件同时触发epoll,则多个事件会被联合在一起返回。
5、epoll_wait会一直监听epollhup事件发生,所以其不需要添加到events中。
6、为了避免大数据量io时,et模式下只处理一个fd,其他fd被饿死的情况发生。linux建议可以在fd联系到的结构中增加ready位,然后epoll_wait触发事件之后仅将其置位为ready模式,然后在下边轮询ready fd列表。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/firo_baidu/archive/2011/01/27/6167158.aspx
分享到:
相关推荐
王健伟老师(51CTO或者其他平台)的课程,学习辅助资料,帮助理解 (已更新,看资源的下一版本)
(牛客网C++课程)Linux 高并发Web服务器项目实战(带定时检测代码) 技术框架: 1. 线程池 + 非阻塞 socket + epoll + 事件处理的并发模型 2. 状态机解析HTTP请求 3. 心跳机制 4. 简易日志系统 主要内容: 1. ...
2-1 高并发网络模型select_epoll_iocp区别 2-2 libevent接口分析 2-3 libevent服务端接收连接的代码示例 2-4 libevent上下文属性配置和源码分析 2-5 获取系统所支持的网络模型例如epoll_select 2-6 配置特征_例如...
│ 高并发编程第一阶段31讲、如何给你的应用程序注入钩子程序,Linux下演示.mp4 │ 高并发编程第一阶段32讲、如何捕获线程运行期间的异常.mp4 │ 高并发编程第一阶段33讲、ThreadGroup API介绍之一.mp4 │ 高...
Linux 网络编程——并发服务器的三种实现模型,相关教程如下: http://blog.csdn.net/tennysonsky/article/details/45671215
在linux下的socket编程服务器模型之多路复用I/O,源码经过本人编译,测试,绝对能正确运行。
Linux 下 UDP 网络编程的基本服务器模型步骤、循环服务器模型步骤和并发服务器模型步骤,包括代码和步骤注释
1.网络编程概要.mkv2.一个TCP的简单实验.mkv3.课程内容大纲.mkv4.回顾基础的Sockets API.mkv5.TTCP代码概览.mkv6.使用TTCP进行网络传输性能测试.mkv7.阻塞IO下的TTCP实验.mkv8.TCP自连接.mkv9.扩展练习.mkv10.时钟...
Linux 下 TCP 网络编程的基本服务器模型步骤、循环服务器模型步骤和并发服务器模型步骤,包括代码和步骤注释
│ 高并发编程第一阶段31讲、如何给你的应用程序注入钩子程序,Linux下演示.mp4 │ 高并发编程第一阶段32讲、如何捕获线程运行期间的异常.mp4 │ 高并发编程第一阶段33讲、ThreadGroup API介绍之一.mp4 │ 高...
linux操作系统下通过Select和Poll两种模型实现的高并发的通信服务程序示例
为了适应不同读者的需要,本书从最基本的Linux系统操作到网络技术的基本理念,逐步深入至Linux/UNIX下具体的编程实践,结合大量具体实例和编程经验,为读者展现Linux平台下网络编程的魅力。 全书由13章组成,内容...
大并发服务器编程模型 windows iocp完成端口模型可支持1万大并发,但是linux能作到5万大并发
LinuxC编程一站式学习.pdf unix程序员手册.pdf 多线程服务器的常用编程模型.pdf 网络编程模型综述.doc 高性能高并发服务器架构.rar Linux环境并发服务器设计技术研究.pdf 应用SELECT模型实现TCP并发服务器.pdf ...
《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。...
3.2.4 IP地址、网络地址和网络掩码 3.2.5 传输层端口 3. 3 域名系统 3.4 域名解析和名字服务器 3. 4. 1 TCP协议 3.4.2 TCP的确认和超时重发机制 3.4.3 TCP头部格式(HeaderFFormat) ...
8.1 服务器模型 8.1.1 CS模型 8.1.2 P2P模型 8.2 服务器编程框架 8.3 IO模型 8.4 两种高效的事件处理模式 8.4.1 Reactor模式 8.4.2 Proactor模式 8.4.3 模拟Proactor模式 8.5 两种高效的并发模式 ...
算法 C / C ++ 数据结构 操作系统与Linux 计算机网络 网络编程 信息安全 :high_voltage: :star: ...五种IO编程模型,并发服务器模型等重点面试必考题。 类别加密算法,网络通信安全等重点面试必考题。
socket网络编程-epoll-水平触发和边缘触发源码。 (1)I/O多路复用技术用于监控多个TCP连接上的数据收发,而epoll就是一种在Linux上使用的I/O多路复用并支持高并发的典型技术。传统的select、poll也是I/O多路复用...
在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样: 当用户进程调用了recvfrom这个系统调用,kernel内核就开始了IO的第一个阶段:准备数据。对于network io( 网络io )来说,很多时候...