最好的参考资料:
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
分享到:
相关推荐
这门技术涉及如何在Linux环境下编写程序,实现网络通信,包括TCP/IP协议栈、套接字编程、并发服务处理等多个方面。以下是对这个主题的详细阐述: 一、TCP/IP协议栈 TCP/IP协议栈是互联网通信的基础,它由四层组成:...
包括发消息互斥量、连接相关互斥量、连接回收队列相关互斥量等资源的初始化,以及epoll相关技术的使用,都说明了在高并发编程中需要特别注意资源竞争和同步问题。 8. Nginx架构与工作模式: Nginx作为一个高性能的...
Python网络编程在Linux环境下是一个强大的工具,用于构建服务器端应用程序和服务。这个主题涵盖了多个关键知识点,包括基础概念、Python的网络库...同时,对于深入理解网络协议、操作系统原理和并发编程也有很大帮助。
- 编程模型:包括同步阻塞、同步非阻塞、异步回调和多线程/进程模型。 - TCP编程:面向连接,提供可靠传输,适用于需要保证数据完整性的场景。 - UDP编程:无连接,提供简单快速的数据传输,适用于对实时性要求高...
总之,"网络编程模型示例"展示了如何在C++中实现事件驱动的网络服务器,利用Linux的系统调用处理并发连接和数据交换。理解和实践这样的示例有助于提升对网络编程、并发处理以及C++在系统编程方面的理解。
《Linux与UNIX网络编程》是一本深入探讨操作系统层面网络编程的经典教材,主要涵盖了Linux和UNIX系统下的并发编程以及网络通信的实现。这份压缩包中包含的源码是学习这一主题的重要参考资料,它允许读者深入理解网络...
### Linux C 网络编程知识点详解 #### 一、概论 - **网络的历史**:从最初的ARPANET到现代互联网的演变过程。 - **OSI模型**:七层模型,分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。 - *...
### libevent C++高并发网络编程 #### 一、Windows平台编译libevent及环境安装 **1.1 Windows平台编译libevent分析及环境安装** - **环境准备**: 在开始之前,确保已经安装了Visual Studio 2017或更高版本。此外...
《Linux网络编程》一书是Linux环境下学习网络编程的重要参考资料,尤其适合那些对Linux系统有浓厚兴趣并希望深入理解网络编程的读者。本书涵盖了Linux网络编程的基础知识、核心技术以及高级应用,旨在帮助读者掌握在...
8. **异步I/O**: 异步I/O模型如libevent、libev和Boost.Asio,能提高网络服务的性能和可扩展性,是高级网络编程的重要内容。 9. **安全编程**: 在网络编程中,应关注安全问题,如SSL/TLS加密、防止缓冲区溢出、输入...
以下是关于Linux网络编程的一些核心知识点,从OSI模型、进程间通信、套接字编程、到安全性和高级网络编程的主题。 1. Linux进程间通信(IPC) 进程间通信是指在Linux操作系统中,一个进程与另一个进程之间传递信息...
3. **套接字编程模型**:学习如何利用socket API在Linux下进行网络通信,包括创建套接字、绑定地址、监听连接请求等关键步骤。 #### (二)实践篇 1. **TCP服务器与客户端编程**:通过具体实例展示如何使用C语言在...
5. **异步编程与非阻塞I/O**:非阻塞I/O和异步编程模型如AIO(Asynchronous I/O)可以提高程序的响应性,尤其是在高并发场景下。 6. **网络安全**:理解SSL/TLS加密机制,以及如何在Linux网络程序中实现安全通信,...
本篇文章旨在深入解读“黑马_Linux网络编程-网络基础-socket编程-高并发服务器”相关的核心概念和技术要点,包括网络基础知识、常用网络协议、网络应用程序设计模式以及分层模型等内容。 #### 网络基础 网络基础...
《Linux网络编程》是张斌先生的一部专著,深入浅出地讲解了在Linux操作系统环境下进行网络编程的各种技术和实践。这本书涵盖了网络编程的基础概念、协议、API使用以及实际问题的解决方案,对于想要掌握Linux网络编程...
在这个领域,开发者需要掌握Socket编程、网络协议栈的工作原理、多线程/多进程模型、并发处理策略等关键知识点。 1. **Socket编程**: Socket是网络通信的基础接口,它提供了进程间通信(IPC)的能力,特别是在...
在Linux系统中进行网络编程是理解和构建网络应用程序的关键,这涉及到socket编程、网络协议、并发处理等多个方面。 一、Linux操作系统概述 Linux是一种开源、免费的操作系统,它的内核提供了丰富的网络功能,支持...