朴素、Select、Poll和Epoll网络编程模型实现和分析——Epoll模型
在阅读完《朴素、Select、Poll和Epoll网络编程模型实现和分析——Select模型》和《朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型》两篇文章后,我们发现一个问题,不管select函数还是poll函数都不够智能,它们只能告诉我们成功、失败或者超时。如果成功,我们需要遍历整个数组去检查哪些socket需要被处理。对于性能有严格要求的服务器来说,这种浪费的行为是不可容忍的。而本文介绍的Epoll模型就完美的解决了这个问题。(转载请指明出于breaksoftware的csdn博客)
和Poll模型类似,Epoll模型对同时处理的Socket没有限制。但是我们使用Epoll模型时需要定义epoll_event类型的结构体数组
struct epoll_event ev, events[SOCKET_LIST_COUNT];
创建Socket、绑定端口和开始监听等操作和《朴素、Select、Poll和Epoll网络编程模型实现和分析——Select模型》一文中一致,本文就不再列出代码。
和其他几种模式不同,epoll模型需要创建一个epoll文件描述符。
int epfd, nfds;epfd = epoll_create1(0);
之后我们将对该epoll文件描述符进行操作。在进行操作之前,我们先了解下EPOLL的模式:ET和LT模式。这块内容网上很多,我就大概说下。
ET是边界触发(edge-triggered),它的特点是一旦被监控的文件描述符状态发生改变,就会通知应用层,应用层需要“一次性”完成完该事件对应的操作(读或者写等)。如果没有全部完成(比如读/写了一半),ET模式就认为是全部完成了,故不再通知该文件描述符本次事件未完成。它是EPOLL模型中第一个被开发出来的模式,但是由于种种原因,后来又引入了LT模式。
LT是level-triggered。它并不要求用户一次性完成本次事件对应操作,如果操作没有完成,则下次还会通知应用层。所以这种模式是非常安全的。它也是Epoll模型中缺省方式。
至于网上很多人说ET模式比LT模式效率高很多,我觉得这个观点从原理上来说是成立的,但是到实际应用时,可能它们的效率是差不多的。但是这些关于效率的话题,只有测试数据才是有力的证据,其他都是理论推理。
再回到我们的程序上来,我们定义之后接入的socket需要关注的消息以及模式,我们暂且使用ET模式吧。
in_events = EPOLLIN | EPOLLET;out_events = EPOLLOUT | EPOLLET;
下一步,我们将创建的监听socket加入到epoll文件描述符关联的信息中
ev.data.fd = listen_sock;ev.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev);
此时,我们让监控的事件events是EPOLLIN,即发生读事件。且我们使用了缺省模式——LT模式。这样我们可以保证接入的socket将不会因为意外而被丢弃,从而尽可能的保证不丢包。
最后,我们还是要在一个死循环中不停监听相关事件
while (1) {nfds = epoll_wait(epfd, events, sizeof(events), 500);
epoll_wait中第一个参数是epoll文件描述符,第二个参数是用于保存发生事件的epoll_event对象数组;第三个参数是该数组的最大个数;第四个参数是等待的超时时间。注意一下第二个参数,我们传入的是数组首地址。当被监控的socket有被关注的事件发生时,events数组里将保存它的一个副本。这样就让发生了事件的元素保存到该数组中,而没有发生的则不在这个数组中,之后我们就不用遍历整个数组了。epoll_wait函数在执行成功时,将返回填充到events数组中的元素个数。于是我们就开始遍历这个“全部有效”的数组。
for (index = 0; index < nfds; ++index) {int fd = events[index].data.fd;
和Select、Poll模型类似,我们需要区分文件描述符是否是监听socket。如果是监听socket,则通过accept获取接入的socket,并使用epoll_ctl将该socket和epoll文件描述符产生关联。
if (fd == listen_sock) {int new_sock;new_sock = accept(fd, NULL, NULL);if (new_sock < 0) {if (errno == EMFILE) {}else {perror("accept error");exit(EXIT_FAILURE);}}else {request_add(1);ev.data.fd = new_sock;ev.events = in_events;epoll_ctl(epfd, EPOLL_CTL_ADD, new_sock, &ev);}}
如果不是监听socket,那就是之后接入的socket。我们需要判断下发生的事件类型,如果是发生了可读事件,则我们去读该文件描述符,并使用epoll_ctl将该文件描述符的状态改成“可写”。
else {if (events[index].events & EPOLLIN) {if (0 != server_read(fd)) {close(fd);epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);}else {events[index].events = out_events;epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &events[index]);}}
如果是接入的socket是写状态,我们就写入数据。最后关闭该连接,同时使用epoll_ctl将该文件描述符和epoll文件描述符断开关系。
else if (events[index].events & EPOLLOUT) {server_write(fd);close(fd);//memset(&events[index], 0, sizeof(events[index]));//events[index].data.fd = -1;epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);}}}}close(epfd);return 0;
}
一切就是这么简单。我们看下epoll模型的执行效率。我们采用和《朴素、Select、Poll和Epoll网络编程模型实现和分析——朴素模型》一文中相同的环境和压力,看下服务器的数据输出
再看下客户端输出
可见在当前环境下,每秒可以处理11000左右个请求。可见它的效率的确比Select和Poll模型好。
相关文章:

Scala 深入浅出实战经典 第88讲:Scala中使用For表达式实现map、flatMap、filter
高级函数 map,flatMap,filter用for循环的实现。package com.dt.scala.forexpressionobject For_Advanced {def main(args: Array[String]) {}def map[A, B](list: List[A], f: A > B): List[B] for(element <- list) yield f(element)def flatMap[A, B](list: List[A], f…
抛弃Python,我们为什么用Go编写机器学习架构?
所有参与投票的 CSDN 用户都参加抽奖活动群内公布奖项,还有更多福利赠送作者 | Caleb Kaiser译者 | 弯月,编辑 | 郭芮来源 | CSDN(ID:CSDNnews)如今,众所周知Python是机器学习项目中最流行的语言。尽管R、C…
朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较
经过之前四篇博文的介绍,可以大致清楚各种模型的编程步骤。现在我们来回顾下各种模型(转载请指明出于breaksoftware的csdn博客) 模型编程步骤对比《朴素、Select、Poll和Epoll网络编程模型实现和分析——朴素模型》中介绍的是最基本的网络编程…

使用VM虚拟机的一点小技巧
今天想为朋友弄一个虚拟机系统文件,这样就可以直接拷贝过去,直接让他用了。哪成想电脑里的系统镜像文件不能用,也不知道是不是VM不支持,反正怎么着也引导不起来了。无奈只好用硬件光驱来装虚拟系统,把2003系统盘装入光…
翻译:AKKA笔记 - Actor消息 -1(二)
消息 我们只是让QuoteRequest到ActorRef去但是我们根本没见过消息类! 它是这样的:(一个最佳实践是把你的消息类包装在一个完整的对象里以利于更好的组织) TeacherProtocol package me.rerun.akkanotes.messaging.protocolsobject …

远程安装oracle 10.2.1 for redhat 5.0 2.6.18-53.el5xen
远程安装oracle <?xml:namespace prefix st1 ns "urn:schemas-microsoft-com:office:smarttags" />10.2.1 for redhat 5.0 2.6.18-53.el5xen<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />今天有个朋友打电…
伯克利新无监督强化学习方法:减少混沌所产生的突现行为
作者 | Glen Berseth译者 | Arvin编辑 | 夕颜出品 | AI科技大本营(ID: rgznai100)【导读】所有生命有机体都在环境中占据一席之地,使它们在周围不断增加的熵中可以保持相对可预测性。例如,人类竭尽全力保护自己免受意外袭击--我们…
朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll、Epoll模型处理长连接性能比较
在《朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较》一文中,我们分析了各种模型在处理短连接时的能力。本文我们将讨论处理长连接时各个模型的性能。(转载请指明出于breaksoftware的csdn博客) 我们可以想象下场景,…

Topcoder SRM 663 DIV 1
ABBADiv1 题意: 规定两种操作,一种是在字符串的末尾添加A,另一种是在末尾添加B然后反转字符串。现在给你一个起始串,一个终点串,然后问你是否能够通过以上两种操作,从起始串变为终点串。 题解: …
跨平台PHP调试器设计及使用方法——立项
作为一个闲不住且希望一直能挑战自己的人,我总是在琢磨能做点什么。自从今年初开始接触PHP,我也总想能在这个领域内产生点贡献。那能做点什么呢?我经常看到很多phper说自己设计了一个什么框架,或者说自己搭建了一个什么系统。虽然…
机器推理文本+视觉,跨模态预训练新进展
作者 | 李根、段楠、周明来源 | 微软研究院AI头条(ID:MSRAsia)【导读】机器推理要求利用已有的知识和推断技术对未见过的输入信息作出判断,在自然语言处理领域中非常重要。本文将介绍微软亚洲研究院在跨模态预训练领域的研究进展。近年来&…

[LeetCode]:94:Binary Tree Inorder Traversal
题目: Given a binary tree, return the inorder traversal of its nodes values. For example:Given binary tree {1,#,2,3}, 1\2/3return [1,3,2]. 代码: public class Solution {public static ArrayList<Integer> listResult new ArrayList&l…
腾讯 AI 2019这一年
所有参与投票的 CSDN 用户都参加抽奖活动群内公布奖项,还有更多福利赠送近日,腾讯AI实验室总结了 2019 年其取得重大进展的两大研究方向,推动实现的行业应用以及前沿研究探索方面的成果。一、两大难题攻坚:通用人工智能与数字人用…
跨平台PHP调试器设计及使用方法——探索和设计
在《跨平台PHP调试器设计及使用方法——立项》一文中,我确定了使用xdebug作为调试器插件部分的基础组件。xdebug提供了一个远程调试的功能(相关资料可以详见https://xdebug.org/docs/remote),我们这个项目便是基于这个功能实现的。…

Ubuntu下允许Root用户直接登录图形界面
ubuntu root是默认禁用了,不允许用root登陆,所以先要设置root密码。 执行:sudo passwd root 接着输入密码和root密码,重复密码。再重新启动就可以用root登陆。 另外,默认情况下是不允许用root帐号直接登陆图形界面的。…

携程App for Apple Watch探索
在Apple Watch发布之后,很多App都针对它设计了相应的版本。旅行作为与Apple Watch时间管理特性契合度较高的场景,同时携程旅行作为国内领先的OTA行业App,也成为了首批适配Apple Watch并荣登Apple官网和App Store推荐的应用之一。InfoQ就App f…
跨平台PHP调试器设计及使用方法——通信
首先引用《跨平台PHP调试器设计及使用方法——探索和设计》中的结构图(转载请指明出于breaksoftware的csdn博客) 本文要介绍的是我们逻辑和pydbgp通信的实现(图中红框内内容)。 设计通信之前,我需要先设计一种通信协议…

MVP模式的相关知识
MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Mod…
“数学不行,还能干点啥?”面试官+CTO:干啥都费劲!
关于数学与程序员的“暧昧”关系,先看看网友的看法:同时编程圈也流传着一个段子:一流程序员靠数学,二流程序员靠算法,末端程序员靠百度,低端看高端就是黑魔法。想一想,我们日常学习、求职、工作…

CentOS7 yum 源的配置与使用
YUM:Yellowdog Updater Modified Yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器。基于RPM包管理,能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖…

跨平台PHP调试器设计及使用方法——协议解析
在《跨平台PHP调试器设计及使用方法——探索和设计》一文中,我介绍了将使用pydbgp作为和Xdebug的通信库,并让pydbgp以(孙)子进程的方式存在。《跨平台PHP调试器设计及使用方法——通信》解决了和pydbgp通信的问题,本文…

测试客户端发图图
转载于:https://blog.51cto.com/ericsong/116942
搜狐、美团、小米都在用的Apache Doris有什么好? | BDTC 2019
【导读】12 月 5-7 日,由中国计算机学会主办,CCF 大数据专家委员会承办,CSDN、中科天玑协办的中国大数据技术大会(BDTC 2019)在北京长城饭店隆重举行。100 顶尖技术专家、1000 大数据从业者齐聚于此,以“大…

cacti邮件告警设置
功能说明对指定流量图形(指定接口)设置最高或最低流量阀值,当流量出现异常偏高或偏低触发阀值,系统自动将异常信息以邮件形式通知指定收件人。如果收件人邮箱是139邮箱,还可以增设短信通知功能。设置前准备设置该功能之…
跨平台PHP调试器设计及使用方法——高阶封装
在《跨平台PHP调试器设计及使用方法——协议解析》一文中介绍了如何将pydbgp返回的数据转换成我们需要的数据。我们使用该问中的接口已经可以构建一个简单的调试器。但是由于pydbgp存在的一些问题,以及调试器需要的一些高级功能,我们还需要对这些接口进行…

Oracle的口令文件(passwordfile)的讲解(摘录)
初学oracle,很多概念迷糊,今天看到这文章,让我有一个比较清晰的认识。转载[url]http://www.itpub.net/viewthread.php?tid906008&extra&page1[/url]1、os认证oracle安装之后默认情况下是启用了os认证的,这里提到的os认证…
如何优雅地使用pdpipe与Pandas构建管道?
作者 | Tirthajyoti Sarkar译者 | 清儿爸编辑 | 夕颜出品 | AI科技大本营(ID: rgznai100) 【导读】Pandas 是 Python 生态系统中的一个了不起的库,用于数据分析和机器学习。它在 Excel/CSV 文件和 SQL 表所在的数据世界与 Scikit-learn 或 Te…

第 十 天 : 添 加 硬 盘 和 分 区 挂 载 等
小Q:狼若回头,必有缘由,不是报恩,就是***; 事不三思必有败,人能百忍则无忧。今天的进度虽然慢了,但是学习状态还是一如往常,只不过今天遇到了不少新的知识点,需要好好想想…
从4个月到7天,Netflix开源Python框架Metaflow有何提升性能的魔法?
作者 | Rupert Thomas译者 | 凯隐编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导语】Metaflow 是由 Netflix 开发,用在数据科学领域的 Python框架,于 2019 年 12 月正式对外开源。据介绍,Metaflow 解决…
SOA标准发展混乱 国内业务缺少经验
近年来,SOA已经成为国际及我国信息技术领域的重大热点之一。从2005年至今,SOA逐渐成为影响中国IT系统构建的主导思想。从2006年开始,SOA的建设方法已在我国部分行业信息化项目中开始得以越来越广泛的应用。 但热潮背后, SOA概念在…