epoll ET(边缘触发) LT(水平触发)
Edge Triggered (ET) 边缘触发只有数据到来,才触发,不管缓存区中是否还有数据。
Level Triggered (LT) 水平触发只要有数据都会触发。
首先介绍一下LT工作模式:
LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表.
优点:当进行socket通信的时候,保证了数据的完整输出,进行IO操作的时候,如果还有数据,就会一直的通知你。
缺点:由于只要还有数据,内核就会不停的从内核空间转到用户空间,所有占用了大量内核资源,试想一下当有大量数据到来的时候,每次读取一个字节,这样就会不停的进行切换。内核资源的浪费严重。效率来讲也是很低的。
ET:
ET(edge-triggered)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知。请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once).
优点:每次内核只会通知一次,大大减少了内核资源的浪费,提高效率。
缺点:不能保证数据的完整。不能及时的取出所有的数据。
应用场景: 处理大数据。使用non-block模式的socket。
例子:
//《client》 #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #define MAXLINE 10 #define SERV_PROT 8001 int main(void) { struct sockaddr_in seraddr, cliaddr; char buf[MAXLINE]; int connfd, i; char ch = 'a'; connfd = socket(AF_INET,SOCK_STREAM,); bzero(&cliaddr,sizeof(cliaddr)); cliaddr.sin_family = AF_INET; cliaddr.sin_port = htons(SERV_PROT); cliaddr.sin_addr.s_addr = htonl(INADDR_ANY); connect(connfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)); ){ ;i < MAXLINE;i++){ buf[i] = ch; } buf[i-] = '\n'; ch++; for(;i<MAXLINE;i++) buf[i] = ch; ch++; write(connfd, buf, sizeof(buf)); sleep(); } close(connfd); ; }
以上代码由于浏览器不支持粘贴,所以全部手打,如有错误,稍微调试即可。由于代码简单就不解释代码的意思了。。。。
//《server》 #include <stdio.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/epoll.h> #include <unistd.h> #define MAXLINE 10 #define SERV_PORT 8000 int main(void) { struct sockaddr_in servaddr, cliaddr; socklen_t cliaddr_len; int listenfd, connfd; char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; int i, efd; listenfd = socket(AF_INET, SOCK_STREAM, ); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd, ); struct epoll_event event; ]; int res, len; efd = epoll_create(); /* ET 边沿触发 ,默认是水平触发 */ event.events = EPOLLIN | EPOLLET; /* event.events = EPOLLIN; */ printf("Accepting connections ...\n"); cliaddr_len = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port)); event.data.fd = connfd; epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &event); ) { res = epoll_wait(efd, resevent, , -); printf("res %d\n", res); ].data.fd == connfd) { len = read(connfd, buf, MAXLINE/); write(STDOUT_FILENO, buf, len); } } ; }
此时服务器端如果使用lt模式:启动server,启动client,运行结果:
res 1
aaaa
res 1
bbbb
过5s ........
如果使用et模式 运行结果:
res 1
aaaa
过5s
res 1
bbbb
。。。。。。
所有当我们使用ET模式的时候,需要使用非阻塞的文件描述符。即对connfd使用fcntl改为非阻塞
即:
#include <stdio.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/epoll.h> #include <unistd.h> #include <fcntl.h> #define MAXLINE 10 #define SERV_PORT 8000 int main(void) { struct sockaddr_in servaddr, cliaddr; socklen_t cliaddr_len; int listenfd, connfd; char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; int i, efd, flag; listenfd = socket(AF_INET, SOCK_STREAM, ); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd, ); struct epoll_event event; ]; int res, len; efd = epoll_create(); /* ET 边沿触发 ,默认是水平触发 */ event.events = EPOLLIN | EPOLLET; /* event.events = EPOLLIN; */ printf("Accepting connections ...\n"); cliaddr_len = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port)); /*fcntl可实现对指定文件描述符的各种操作, F_GETFL读取文件状态标识*/
flag = fcntl(connfd, F_GETFL); flag |= O_NONBLOCK; fcntl(connfd, F_SETFL, flag); event.data.fd = connfd; epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &event); ) { printf("epoll_wait begin\n"); res = epoll_wait(efd, resevent, , -); printf("epoll_wait end res %d\n", res); ].data.fd == connfd) { )) > ) write(STDOUT_FILENO, buf, len); } } ; }
添加了以上代码;运行结果为:
epoll_wait begin
epoll_wait end res 1
aaaa
bbbb
epoll_wait begin
过5秒
epoll_wait end res 1
cccc
dddd
由此可以看出已经恢复了正常 。一次性全部读出了全部的数据,当没有数据的时候,read返回-1,结束循环继续监听。。。。
epoll ET(边缘触发) LT(水平触发)的更多相关文章
- epoll的边缘触发与水平触发
epoll的边缘触发与水平触发 Tcp连接是双向的,内核为每个socket维护两个缓冲区,读缓冲区与写缓冲区,内核会一个关注这两个缓冲区,当采用水平触发时,对于写缓冲区而言,如果有多余空间可写,对于读 ...
- 实例浅析epoll的水平触发和边缘触发,以及边缘触发为什么要使用非阻塞IO
一.基本概念 我们通俗一点讲: Level_triggered(水平触发):当被监控的 ...
- epoll的水平触发和边缘触发,以及边缘触发为什么要使用非阻塞IO
转自:http://www.cnblogs.com/yuuyuu/p/5103744.html 一.基本概念 ...
- Linux网络编程之select、poll、epoll的比较,以及epoll的水平触发(LT)和边缘触发(ET)
Linux的网络通信先后推出了select.poll.epoll三种模式. select有以下三个问题: (1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大. ...
- Linux系统编程——水平触发和边沿触发
事件模型 EPOLL事件有两种模型: Edge Triggered (ET) 边缘触发只有数据到来才触发,不管缓存区中是否还有数据. Level Triggered (LT) 水平触发只要有数据都会触 ...
- jenkins 判断是手动触发还是定时器触发
根据变量BUILD_CAUSE的值可以判断本次触发是手动触发还是定时器触发 手动触发:MANUALTRIGGER 定时器触发:TIMERTRIGGER
- Unity插件之NGUI学习(6)—— 关于Widget怎样加入触发事件(触发OnClick)
NGUI中,Button本身就带有OnClick事件,可是Sprite,Label等( 也绑有Widget的)并没有触发事件,事实上NGUI的事件触发都必须加入Box Collider,并勾选Is T ...
- EasyUI触发方法、触发事件、创建对象的格式??
创建对象 $("选择器").组件名({ 属性名 : 值, 属性名 : 值 }); 触发方法 $("选择器").组件名("方法名",参数); ...
- 利用epoll写一个"迷你"的网络事件库
epoll是linux下高性能的IO复用技术,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率.另一点原因就是获取 ...
随机推荐
- jsp用el表达式获取后台传来的值,或者获取session中的值
<script type="text/javascript"> var usernameC = ${sessionScope.SESSION_USER_PROFILE. ...
- Git代码管理
持续更新中... 有道笔记链接:http://note.youdao.com/noteshare?id=10a0a86a3499f92cf26371f2698b97d2 Git网上平台 Git ...
- TinScrapy-简化的Scrapy原码-查看爬虫的执行流程
学习了自定义的TinyScrapy框架,整理出以下定注释的代码 from twisted.web.client import getPage,defer from twisted.internet i ...
- HybridStart混合应用开发框架
转自我的博客,原文地址:http://refined-x.com/2017/06/26/%E5%9F%BA%E4%BA%8EAPICloud%E7%9A%84%E6%B7%B7%E5%90%88%E5 ...
- 上传本地文件到GitHub上
问题解决 今天在windows上上传本地文件到github,出现用户名和仓库不匹配的情况,解决方式如下: 打开控制面板,选择用户账户 把该删除的账户删除一下就行了. 上传文件的步骤如下: 将上传的文件 ...
- nuxt axios代理
modules: [ '@nuxtjs/axios', ], axios: { //prefix: '/api/', proxy: true // Can be also an object with ...
- android系统中如何通过程序打开某个AccessibilityService
android系统中如何通过程序打开某个AccessibilityService(系统辅助服务)? 通常的做法是注册AccessibilityService(辅助服务)后跳转到设置启动服务页面引导用户 ...
- 苹果手机连接Wifi认证机制
Wifi状态保持方法和nas设备 https://patents.google.com/patent/CN106793171A/zh 基于ios终端的离线wifi热点认证方法和认证系统 https:/ ...
- C# 对文本文件的几种读写方法总结
计算机在最初只支持ASCII编码,但是后来为了支持其他语言中的字符(比如汉字)以及一些特殊字符(比如€),就引入了Unicode字符集.基于Unicode字符集的编码方式有很多,比如UTF-7.UTF ...
- Golang 入门系列(十) mysql数据库的使用
之前,已经讲过一些Golang的基础的东西,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 今天简 ...