epoll的优点:1.支持一个进程打开大数目的socket描述符(FD)

select 最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048。对于那些需要支持的上万连接数目的IM服务器来说显然太少了。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的 Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也不是一种完美的方案。不过 epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat

/proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。

2.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.使用mmap加速内核与用户空间的消息传递。

这点实际上涉及到epoll的具体实现了。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。而如果你想我一样从2.5内核就关注epoll的话,一定不会忘记手工 mmap这一步的。

4.内核微调

这一点其实不算epoll的优点了,而是整个linux平台的优点。也许你可以怀疑linux平台,但是你无法回避linux平台赋予你微调内核的能力。比如,内核TCP/IP协议栈使用内存池管理sk_buff结构,那么可以在运行时期动态调整这个内存pool(skb_head_pool)的大小--- 通过echo XXXX>/proc/sys/net/core/hot_list_length完成。再比如listen函数的第2个参数(TCP完成3次握手的数据包队列长度),也可以根据你平台内存大小动态调整。更甚至在一个数据包面数目巨大但同时每个数据包本身大小却很小的特殊系统上尝试最新的NAPI网卡驱动架构。

Epoll 的高效和其数据结构的设计是密不可分的,这个下面就会提到。

首先回忆一下 select 模型,当有 I/O 事件到来时, select 通知应用程序有事件到了快去处理,而应用程序必须轮询所有的 FD 集合,测试每个 FD 是否有事件发生,并处理事件;代码像下面这样:

int res = select(maxfd+1, &readfds, NULL, NULL, 120);

if (res > 0)

{

for (int i = 0; i < MAX_CONNECTION; i++)

{

if (FD_ISSET(allConnection[i], &readfds))

{

handleEvent(allConnection[i]);

}

}

}

// if(res == 0) handle timeout, res < 0 handle error

Epoll 不仅会告诉应用程序有I/0 事件到来,还会告诉应用程序相关的信息,这些信息是应用程序填充的,因此根据这些信息应用程序就能直接定位到事件,而不必遍历整个FD 集合。

int res = epoll_wait(epfd, events, 20, 120);

for (int i = 0; i < res;i++)

{

handleEvent(events[n]);

}

Epoll 关键数据结构

前面提到 Epoll 速度快和其数据结构密不可分,其关键数据结构就是:

struct epoll_event {

__uint32_t events; // Epoll events

epoll_data_t data; // User data variable

};

typedef union epoll_data {

void *ptr;

int fd;

__uint32_t u32;

__uint64_t u64;

} epoll_data_t;

可见 epoll_data 是一个 union 结构体

, 借助于它应用程序可以保存很多类型的信息

:fd 、指针等等。有了它,应用程序就可以直接定位目标了。

使用 epoll

既然 Epoll 相比 select 这么好,那么用起来如何呢?会不会很繁琐啊 … 先看看下面的三个函数吧,就知道 Epoll 的易用了。

int epoll_create(int size);

生成一个 Epoll 专用的文件描述符,其实是申请一个内核空间,用来存放你想关注的 socket fd 上是否发生以及发生了什么事件。 size 就是你在这个 Epoll fd 上能关注的最大 socket fd 数,大小自定,只要内存足够。

int epoll_ctl(int epfd, int op,

int fd, struct epoll_event *event );

控制某个 Epoll 文件描述符上的事件:注册、修改、删除。其中参数 epfd 是 epoll_create() 创建 Epoll 专用的文件描述符。相对于 select 模型中的 FD_SET 和 FD_CLR 宏。

int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout);

等待 I/O 事件的发生;参数说明:

epfd: 由 epoll_create()生成的 Epoll 专用的文件描述符;

epoll_event: 用于回传代处理事件的数组;

maxevents: 每次能处理的事件数;

timeout: 等待 I/O 事件发生的超时值;

返回发生事件数。

相对于 select 模型中的 select 函数。

一个简单的epoll程序

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define SERVPORT 9527 /*服务器监听端口号 */

#define BACKLOG 10 /* 最大同时连接请求数 */

void setnonblocking(int sock)

{

int opts;

opts = fcntl(sock,F_GETFL);

if(opts<0)

{

perror("fcntl(sock,GETFL)");

exit(1);

}

opts = opts|O_NONBLOCK;

if(fcntl(sock,F_SETFL,opts)<0)

{

perror("fcntl(sock,SETFL,opts)");

exit(1);

}

}

void do_use_fd(int client_fd)

{

const char str[] = "God bless you!\n";

if (send(client_fd, str, sizeof(str), 0) == -1)

perror("send");

close(client_fd);

}

int main()

{

int sockfd;

struct sockaddr_in my_addr;

struct sockaddr_in remote_addr;

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

perror("socket");

exit(1);

}

my_addr.sin_family = AF_INET;

my_addr.sin_port = htons(SERVPORT);

my_addr.sin_addr.s_addr = INADDR_ANY;

bzero(&(my_addr.sin_zero), 8);

if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {

perror("bind");

exit(1);

}

printf("bind ok\n");

if (listen(sockfd, BACKLOG) == -1) {

perror("listen");

exit(1);

}

printf("listen ok\b");

size_t sin_size = sizeof(struct sockaddr_in);

#define MAX_EVENTS 10

struct epoll_event ev, events[MAX_EVENTS];

int conn_sock, nfds, epollfd;

epollfd = epoll_create(10);

if (epollfd == -1) {

perror("epoll_create");

exit(EXIT_FAILURE);

}

printf("epoll_create\n");

ev.events = EPOLLIN;

ev.data.fd = sockfd;

if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {

perror("epoll_ctl: sockfd");

exit(EXIT_FAILURE);

}

printf("epoll_ctl ok\n");

for (;;) {

printf("start epoll_wait\n");

nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);

if (nfds == -1) {

perror("epoll_pwait");

exit(EXIT_FAILURE);

}

printf("epoll_wait returns, nfds = %d\n", nfds);

for (int n = 0; n < nfds; ++n) {

if (events[n].data.fd == sockfd) {

conn_sock = accept(sockfd,

(struct sockaddr *) &remote_addr, &sin_size);

if (conn_sock == -1) {

perror("accept");

exit(EXIT_FAILURE);

}

setnonblocking(conn_sock);

ev.events = EPOLLIN | EPOLLET;

ev.data.fd = conn_sock;

if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,

&ev) == -1) {

perror("epoll_ctl: conn_sock");

exit(EXIT_FAILURE);

}

} else {

do_use_fd(events[n].data.fd);

}

}

}

}

java epoll 模型_I/O多路复用技术详解之epoll模型相关推荐

  1. java反射源码_java反射技术详解附源码

    在学校学习Java时,由于学的不扎实,也没经历过太多实战项目,所以很多重要的知识点瞟一眼就过去了,比如现在要讲的反射,当时直接就忽略掉了,可现在发现很多地方需要反射,不得不重新学习一下,上学欠了太多债 ...

  2. Tensorflow 2.x(keras)源码详解之第十章:keras中的模型保存与加载(详解Checkpointmd5模型序列化)

      大家好,我是爱编程的喵喵.双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中.从事机器学习以及相关的前后端开发工作.曾在阿里云.科大讯飞.CCF等比赛获得多次Top名次.现 ...

  3. backbone java_Backbone和Angular Java技术详解

    Tomcat系列之Java技术详解 将不同的思想和工具进行对比,是一种更好地理解它们的方式.在本文中,我首先将列举在创建web应用程序时需要重复进行的各项任务,随后为你展现Backbone和Angul ...

  4. 视频直播技术详解(8)直播云 SDK 性能测试模型

    <视频直播技术详解>系列之八:直播云 SDK 性能测试模型 牛小七2016年10月12日发布在 视频直播技术详解 七牛云于 6 月底发布了一个针对视频直播的实时流网络 LiveNet 和完 ...

  5. java技术详解_Java反射技术详解及实例解析

    前言 相信很多人都知道反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的,比如最初的很多注解框架,后来因为java反射影响性能,所以被运行时注解APT替 ...

  6. 《视频直播技术详解》系列之八:直播云 SDK 性能测试模型

    七牛云于 6 月底发布了一个针对视频直播的实时流网络 LiveNet 和完整的直播云解决方案,很多开发者对这个网络和解决方案的细节和使用场景非常感兴趣. 结合七牛实时流网络 LiveNet 和直播云解 ...

  7. java 李刚 pdf_Java数据库技术详解(李刚) PDF_源雷技术空间

    资源名称:Java数据库技术详解(李刚) PDF 第一篇 数据库基础篇 第1章 Java和数据库 2 1.1 Java概述 2 1.1.1 跨平台性 2 1.1.2 面向对象 2 1.1.3 安全性 ...

  8. 视频直播技术详解之直播云SDK性能测试模型

    声明:本文为CSDN原创投稿文章,未经许可,禁止任何形式的转载. 作者:七牛云 责编:钱曙光,关注架构和算法领域,寻求报道或者投稿请发邮件qianshg@csdn.net,另有「CSDN 高级架构师群 ...

  9. OSI(open system internet)七层模型介绍以及NAT(Network Address Translation)技术详解

    文章目录 1- OSI七层模型介绍 2- 物理层 (1)作用 (2)常见协议 3- 数据链路层 (1)作用 (2)常见协议 [1]ARP协议(地址解析) [2]RARP协议(逆地址解析) [3]PPP ...

  10. 新书推荐 |《5G NR物理层技术详解:原理、模型和组件》

    新书推荐 <5G NR物理层技术详解:原理.模型和组件> 点击上图了解及购买 5G专家和学者撰写,详解5G NR物理层技术(包括波形.编码调制.信道仿真和多天线技术等)及其背后的成因,爱立 ...

最新文章

  1. 数据挖掘技术在出行体验上的应用!
  2. mariadb 基础使用
  3. iOS快速开发框架--Bee Framework
  4. 解读三种虚拟化之路连载一:x86虚拟化概述
  5. jquery中Live方法不可用,Jquery中Live方法失效
  6. lambda表达式pythonlist_Python 使用Lambda对list(列表)中指定格式字符串元素排序方法...
  7. Android之drawlayout使用和总结
  8. python删除列表中字符串_python - 删除字符串中的字符列表
  9. ibatis--百度百科
  10. 2017百度之星资格赛 1003 度度熊与邪恶大魔王
  11. left join 多条件_第九篇|Spark的五种JOIN策略解析
  12. mysql的事务日志_MySQL 事务日志
  13. Python3.5(十三)迭代器生成器
  14. [php]laravel框架容器管理的一些要点
  15. SQL Server 2016 完全卸载(安装)全教程
  16. [源码解析] TensorFlow 分布式环境(6) --- Master 动态逻辑
  17. 0606关于mysql优化原理
  18. 打印后台程序服务没有运行,无法添加或使用打印机的处理方法
  19. 数据驱动测试一:使用TestNG进行数据驱动
  20. 惠普 hp3414 笔记本 电脑 驱动 drivers

热门文章

  1. OA系统如何快速做出统计报表
  2. Eucalyptus使用注意事项
  3. 使用jeb转换java语言_JEB 无源码调试 以dvm smali字节码方式,Demo尝试
  4. linux 模板 制作工具,OpenTBS 1.8.0 发布,生成 Office 的模板工具
  5. IntelliJ IDEA使用教程 (总目录篇)
  6. easydarwin 安装_win10安装EasyDarwin并作为流媒体服务器的推流和拉流实例
  7. android studio gradle下载
  8. php7 电子书 下载,php7.3.8中文电子手册
  9. 优秀的WBS的分解标准
  10. Git下载与安装 Windows