- 浏览: 724603 次
- 性别:
- 来自: 北京
最新评论
-
wxweven:
Surmounting 写道既然 Java 的跳表那么少,我决 ...
SkipList 跳表 -
暮雪云然:
写的不错,很透彻
Java静态内部类 -
bzhao:
好,赞扬!
Linux信号详解 -
jacktao219:
赞一个~! ,现在正在看redis 所以接触到跳表
SkipList 跳表 -
is_leon:
vote--后还要判断是否为0吧,如果为0则废掉重新置位can ...
现在有一个整数数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数
epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著减少程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。
一、epoll的优点
支持一个进程打开大数目的socket描述符。
IO效率不随FD数目增加而线性下降。
二、epoll的使用
epoll有2种工作方式:LT和ET。
LT(level triggered,水平触发)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,
内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任操作,
内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型
的代表。
ET (edge-triggered,边缘触发)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未
就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文
件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在
发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是
请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知
(only once)。
epoll相关的系统调用有3个:epoll_create, epoll_ctl和epoll_wait。在头文件<sys/epoll.h>
1. int epoll_create(int size);
创建一个epoll句柄,即图中的epfd, 用来监听事件, size用来告诉内核这个监听的数目一共有多大。
这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。
2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
参数op是操作类型, 使用这个方法完成3种操作:
EPOLL_CTL_ADD:注册新的fd到epfd中;
EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
EPOLL_CTL_DEL:从epfd中删除一个fd;
(1) 注册新事件
struct epoll_event ev; ev.data.fd = fd; ev.events = EPOLLIN; epoll_cntl(epfd, EPOOL_CTL_ADD, fd, &ev);
(2) 修改监听事件
struct epoll_event *a_event = get_a_event() struct epoll_event ev; ev.data.fd = a_event->data.fd; ev.events = a_event->events | EPOLLOUT; epoll_cntl(epfd, EPOOL_CTL_MOD, a_event->data.fd, &ev);
(3) 删除事件
struct epoll_event *a_event = get_a_event() struct epoll_event ev; ev.data.fd = a_event->data.fd; epoll_cntl(epfd, EPOOL_CTL_DEL, a_event->data.fd, &ev);
3种操作都使用了一个ev变量, 这个变量用来关联fd和它的监听事件, 是临时的, 可以反复使用.
ev是一个struct epoll_event结构体, 结构如下:
- typedef union epoll_data {
- void *ptr;
- int fd;
- __uint32_t u32;
- __uint64_t u64;
- } epoll_data_t;
- 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)来说的。
注意多个socket可以设置不同的触发模式
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
等待事件的产生, 把产生的事件存放到events数组里, 如图中所示, 调用epoll_wait后,
fd 1和 fd 3和fd k产生了事件, 把它们分别存放到events[0], events[1], events[2]
参数epfd:epoll_create()函数返回的epoll句柄。
参数events:struct epoll_event结构指针,用来从内核得到事件的集合。
参数 maxevents:告诉内核这个events有多大
参数 timeout: 等待时的超时时间,以毫秒为单位。
返回值:成功时,返回需要处理的事件数目。调用失败时,返回0,表示等待超时。
三 epoll实例 -- 模拟HTTP服务器
#include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <sys/epoll.h> #include <sys/sendfile.h> #include <sys/stat.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <fcntl.h> #include <errno.h> #define MAX_EVENTS 10 #define PORT 8080 //设置socket连接为非阻塞模式 void setnonblocking(int sockfd) { int opts; opts = fcntl(sockfd, F_GETFL); if(opts < 0) { perror("fcntl(F_GETFL)\n"); exit(1); } opts = (opts | O_NONBLOCK); if(fcntl(sockfd, F_SETFL, opts) < 0) { perror("fcntl(F_SETFL)\n"); exit(1); } } int main(){ struct epoll_event ev, events[MAX_EVENTS]; int addrlen, listenfd, conn_sock, nfds, epfd, fd, i, nread, n; struct sockaddr_in local, remote; char buf[BUFSIZ]; //创建listen socket if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("sockfd\n"); exit(1); } bzero(&local, sizeof(local)); local.sin_family = AF_INET; local.sin_addr.s_addr = htonl(INADDR_ANY);; local.sin_port = htons(PORT); if( bind(listenfd, (struct sockaddr *) &local, sizeof(local)) < 0) { perror("bind\n"); exit(1); } listen(listenfd, 20); epfd = epoll_create(MAX_EVENTS); if (epfd == -1) { perror("epoll_create"); exit(EXIT_FAILURE); } ev.events = EPOLLIN; ev.data.fd = listenfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev) == -1) { perror("epoll_ctl: listen_sock"); exit(EXIT_FAILURE); } for (;;) { nfds = epoll_wait(epfd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_pwait"); exit(EXIT_FAILURE); } for (i = 0; i < nfds; ++i) { fd = events[i].data.fd; if (fd == listenfd) { conn_sock = accept(listenfd, (struct sockaddr *) &remote, &addrlen); if (conn_sock == -1) { perror("accept"); exit(EXIT_FAILURE); } setnonblocking(conn_sock); ev.events = EPOLLIN | EPOLLET; ev.data.fd = conn_sock; if (epoll_ctl(epfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { perror("epoll_ctl: add"); exit(EXIT_FAILURE); } continue; } if (events[i].events & EPOLLIN) { n = 0; while ((nread = read(fd, buf + n, BUFSIZ-1)) > 0) { n += nread; } buf[n] = '\0'; ev.data.fd = fd; ev.events = events[i].events | EPOLLOUT; if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) == -1) { perror("epoll_ctl: mod"); } } if (events[i].events & EPOLLOUT) { sprintf(buf, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\nHello World", 11); n = strlen(buf); if (write(fd, buf, n) < n) { perror("write"); } close(fd); } } } return 0; }
运行程序后, 打开浏览器:
发表评论
-
Virtualbox下Windows和Linux实现文件互传
2012-07-17 21:05 33841 Windows安装好Linux虚拟机 2 在Lin ... -
Memcached源码分析之网络模型篇
2012-03-02 01:46 4142memcached 采用多线程的工作方式, 主线程接收连接, ... -
Memcached源码分析之内存管理篇
2012-02-26 15:04 12076使用命令 set(key, value) ... -
多线程与volatile变量
2012-02-25 17:07 5427volatile 修饰的变量表示改变量的值是易变的,编译 ... -
items
2011-11-12 19:30 71 上肢长 2 上臂长 ... -
fds
2011-11-12 19:23 10身高(静态) 眼高 ... -
xml
2011-11-12 18:58 7<item idx = "1" ... -
fff
2011-11-12 18:30 8上肢长 上臂长 两下颌角宽 两眼内宽 两耳屏点间 ... -
(转) memcached采用的网络模型
2011-10-12 01:58 12memcached采用的网络模型 ... -
Nginx 内存池
2011-10-12 01:46 7nginx的内存管理,主要是用来实现防止内存泄露,和内存碎片, ... -
Nginx负载均衡
2011-10-12 01:40 10nginx的upstream目前支持5种方式的分配 ... -
守护进程的实现
2011-09-30 01:43 18476个步骤 步骤1:创建子进程,杀死父进程,目的是为了步 ... -
非阻塞connect的实现
2011-09-30 01:12 14790步骤1: 设置非阻塞,启动连接 实现非阻塞 connect ... -
Memcached内存管理机制
2011-09-29 20:57 2358Slab 分配机制 Memcache ... -
关于大端法和小端法
2011-09-28 23:15 2354typedef union { int n; ... -
vim配置文件精简版
2011-09-19 09:37 1950"Get out of VI's compatibl ... -
(转) Linux 的僵尸(zombie)进程
2011-09-17 20:29 3191原文地址: http://cool ... -
Linux信号详解
2011-09-17 01:02 36355一 信号的种类 可靠信号与不可靠信号, 实时信号与非实时信号 ... -
消息队列
2011-09-15 22:16 12241一 应用场景 有很多业务, 客户端和内网都要进行数据传 ... -
vim + taglist + ctags + cscope 简单使用
2011-09-08 21:58 3560ctags用来跳转, taglist用来列出当前文件的变量, ...
相关推荐
在Linux系统中,`epoll`是用于I/O多路复用的一种高效机制,尤其适合高并发、大连接数的网络应用,如聊天程序。...在阅读和学习时,要重点关注如何创建和管理`epoll`实例,以及如何处理各种I/O事件。
在Linux系统中,`epoll`是用于I/O...综上所述,"Linux C++ epoll使用范例"中的代码可以作为学习和实践`epoll`的参考,通过客户端、服务端及测试程序,读者可以深入理解`epoll`的工作机制,并能实际操作中提升系统性能。
这个示例对于学习网络编程和`epoll`技术非常有帮助,通过实际操作可以加深对这一高级I/O模型的理解。你可以尝试运行这个例子,观察其运行过程,甚至修改代码以实现更复杂的功能,例如添加多线程处理、错误处理机制或...
最后,`分别使用epoll、libevent实现的端口映射程序,学习epoll,libevent.zip`包含了使用Epoll和libevent实现的端口映射程序,有助于比较两种I/O多路复用技术的差异。 综上所述,Epoll是Linux环境下实现高性能网络...
这个Demo对于学习如何在Linux环境下使用QT结合Epoll开发高并发服务器具有很高的参考价值。通过理解Epoll的工作原理和QT的网络编程模型,开发者可以构建出性能优异、能够应对大量并发连接的服务器应用。
1. **性能优化**:epoll使用“红黑树”数据结构存储文件描述符,因此添加、删除和查询的效率更高。 2. **边缘触发与水平触发**:epoll支持边缘触发(EPOLLET)和水平触发(EPOLLONESHOT)。边缘触发只在状态改变时...
【epoll内核代码学习】 epoll是一种高效、可扩展的I/O事件通知机制,用于Linux内核中,尤其适用于高并发的网络编程。...学习epoll的内核代码有助于理解其底层原理,从而更好地优化和利用这一机制。
总的来说,这个压缩包提供了学习和理解epoll如何在实际项目中应用于客户端-服务器通信的一个实例。通过阅读和分析源代码,开发者可以深入理解epoll的用法及其在高性能网络编程中的优势。同时,这也为实现其他基于...
【作品名称】:基于C++使用 epoll + threadpool 实现的 webServer,支持GET、POST 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 ...
可以使用`selectors.EpollSelector`创建一个epoll实例。然后,使用`register`方法将感兴趣的文件描述符(如套接字)注册到epoll实例,指定读写事件。`select`方法用于等待事件发生,并返回一组就绪的文件描述符。 `...
Linux的epoll是一种I/O多路...总之,`linux epoll 例子程序`提供了学习和理解epoll机制的实践平台,通过对这些代码的学习,我们可以深入理解epoll如何提升服务器处理并发能力,并掌握在实际项目中如何运用这一技术。
**epoll_serverANDclient**项目提供了...通过这个项目,我们可以学习如何在C++中使用`epoll`实现高性能的客户端和服务器,理解其在并发I/O处理中的优势。在实际开发中,这种技术常用于构建高可用、高性能的网络服务。
学习epoll、多线程和线程池的知识,首先需要理解它们的基本原理,然后掌握如何在实际项目中应用。对于epoll,需要了解如何创建和管理epoll实例,以及如何正确设置和处理I/O事件。对于多线程,要学习线程的创建、同步...
epoll使用“事件驱动”的模型,允许开发者注册感兴趣的文件描述符(例如,socket套接字),然后在这些描述符上有活动时通知开发者。epoll分为三个主要函数:epoll_create、epoll_ctl和epoll_wait。 1. **epoll_...
- **效率高**:epoll使用红黑树存储监控的文件描述符,添加、删除和查询的复杂度都是O(log(n))。 - **内存拷贝优化**:通过内核空间与用户空间共享内存,减少了数据复制。 - **批量操作**:epoll_wait可以一次...
通过阅读和学习这个代码,初学者不仅能了解epoll的基本用法,还能深入理解如何在实际项目中优雅地封装和使用系统调用,提升系统编程能力。同时,对于开发者来说,这样的封装也便于代码的维护和复用。
Linux下的epoll是一种高效、可扩展的I/O多路复用技术,主要用于处理大量并发连接。它是基于事件驱动的I/O模型,适用于高并发服务器,如Web服务器、...在`epoll.cpp`代码中,我们可以深入学习如何在实践中应用这些概念。
本笔记将深入探讨`epoll`的工作原理、两种主要模式——Edge Triggered (ET) 和 Level Triggered (LT),以及如何在实际编码中使用`epoll`。 首先,`epoll`相比于传统的`select`和`poll`,提供了更高的性能和更灵活的...
这个“Linux下epoll实现简易聊天”项目提供了使用epoll实现简单QQ聊天应用的源代码,旨在帮助开发者了解如何在实际场景中应用epoll。 epoll的核心概念包括以下几点: 1. **I/O多路复用**:I/O多路复用允许单个进程...
1. **效率**: epoll使用“红黑树”数据结构存储文件描述符,添加、删除和查询操作的时间复杂度更低,因此在处理大量文件描述符时性能更优。 2. **边缘触发(Edge Triggered, ET)**: 与水平触发(Level Triggered, LT)...