博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
epoll的lt和et模式的实验
阅读量:6612 次
发布时间:2019-06-24

本文共 6112 字,大约阅读时间需要 20 分钟。

针对epoll api的两种触发模式,lt和et,仿照一些例子写了代码进行实验。

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_EVENT_NUMBER 1024#define BUFFER_SIZE 10int setnonblocking(int fd) { int old_option = fcntl(fd, F_GETFL); int new_option = old_option | O_NONBLOCK; fcntl(fd, F_SETFL, new_option); return old_option;}void addfd(int epollfd, int fd, bool enable_et) { epoll_event event; event.data.fd = fd; event.events = EPOLLIN; if (enable_et) { event.events |= EPOLLET; } epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event); setnonblocking(fd);}void lt(epoll_event *events, int number, int epollfd, int listenfd) { char buf[BUFFER_SIZE]; for (int i=0; i
= 3) { const char *ip =argv[2]; inet_pton(AF_INET, ip, &address.sin_addr); } else { address.sin_addr.s_addr = INADDR_ANY; } address.sin_port = htons(port); int listenfd = socket(PF_INET, SOCK_STREAM, 0); assert(listenfd >= 0); ret = bind(listenfd, (sockaddr*)&address, sizeof(address)); assert(ret != - 1); ret = listen(listenfd, 5); assert(ret != -1); epoll_event events[MAX_EVENT_NUMBER]; int epollfd = epoll_create(5); assert(epollfd != -1); addfd(epollfd, listenfd, true); while(true) { ret = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1); if (ret < 0) { printf("epoll failure\n"); break; } lt(events, ret, epollfd, listenfd); // lt //et(events, ret, epollfd, listenfd); // et } close(listenfd); return 0;}

 

Makefile文件:

epoll_test : epoll_test.cpp        g++ -o epoll_test epoll_test.cpp -lpthread

 

以上程序有个问题,就是在端口被占用时候,因为bind失败,会assert失败然后core dump. 在重复测试时候,可以换个端口。

 

首先,注释掉et,使用lt:

lt(events, ret, epollfd, listenfd); // lt                //et(events, ret, epollfd, listenfd); // et

运行 ./epoll_test 12888 并在另一个窗口用telnet输入超过10个(BUFFERSIZE)字符:

$telnet 127.0.0.1 12888Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.12345678901234567890123456 1234567890123456789012345678

在服务器端得到:

$./epoll_test 12888lt event trigger onceget 9 bytes of content: 123456789lt event trigger onceget 9 bytes of content: 012345678lt event trigger onceget 9 bytes of content: 90123456lt event trigger onceget 1 bytes of content: lt event trigger onceget 9 bytes of content: 123456789lt event trigger onceget 9 bytes of content: 012345678lt event trigger onceget 9 bytes of content: 901234567lt event trigger onceget 3 bytes of content: 8

可以看出因为buffersize的限制,服务器端进行了多次读取,event也触发了多次。

 

换成et模式:

//lt(events, ret, epollfd, listenfd); // lt                et(events, ret, epollfd, listenfd); // et

运行服务器后,telnet客户端输入:

$telnet 127.0.0.1 12889Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.123456789012345678901234561234567890123456789012345678

服务器显示:

$./epoll_test 12889et event trigger onceget 9 bytes of content: 123456789get 9 bytes of content: 012345678get 9 bytes of content: 90123456get 1 bytes of content: read lateret event trigger onceget 9 bytes of content: 123456789get 9 bytes of content: 012345678get 9 bytes of content: 901234567get 3 bytes of content: 8read later

可以看出,每次客户端的字符串,只触发了一次。

 

其实,上面的例子还不够严谨,因为服务器一次已经把字符都读完了。那么如果没读完,会继续出发吗。

如下修改服务器代码:

//修改                        //while (true) {
if (true) { memset(buf, '\0', BUFFER_SIZE); int ret = recv(sockfd, buf, BUFFER_SIZE-1, 0); if (ret < 0) { // Below shows complete if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { printf("read later\n"); break; } printf("some error happens\n"); close(sockfd); //修改 //break; } else if (ret == 0) { close(sockfd); //修改 //break; } else { printf("get %d bytes of content: %s\n", ret, buf); } }

运行服务器之后,telnet输入长字符串:

$telnet 127.0.0.1 12888Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.12345678901234567890123456

服务器端只显示了BUFFERSIZE长度的一行,没有读入的数据也没有进行event触发:

$./epoll_test 12888et event trigger onceget 9 bytes of content: 123456789

如果客户端,再输入一行:

$telnet 127.0.0.1 12888Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.123456789012345678901234561234567890123456789012345678

服务器端也仅仅把之前没读入的上一次客户端发来的数据中,再读入BUFFERSIZE长度:

$./epoll_test 12888et event trigger onceget 9 bytes of content: 123456789et event trigger onceget 9 bytes of content: 012345678

 

另外,对上面的服务器端程序,增加了et模式下对recv函数的返回ret=0的打印:

else if (ret == 0) {                                        printf("get 0 data\n");                                        close(sockfd);                                        break;                                }

发现在et模式下,没有走到ret==0的分支:

$telnet 127.0.0.1 12889Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.12345678901234567890123456

服务器端:

$./epoll_test 12889et event trigger onceget 9 bytes of content: 123456789get 9 bytes of content: 012345678get 9 bytes of content: 90123456get 1 bytes of content: read later

走的是如下的判断结束的分支:

if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {                                                printf("read later\n");                                                break;                                        }

以上。:)

转载于:https://www.cnblogs.com/charlesblc/p/5521086.html

你可能感兴趣的文章
【摘】vbs
查看>>
Android 一键直接查看Sqlite数据库数据
查看>>
HDU - 3506 Monkey Party
查看>>
HashMap实现特点——基于JDK文档
查看>>
C语言最后一次作业--总结报告
查看>>
HttpMessageNotWritableException: Could not write JSON: No serializer found for class ****
查看>>
Django中的RESTful
查看>>
jsp中IE与FF(chrome)request参数编码不同
查看>>
asp.net mssqlserver 存储过程
查看>>
KVM
查看>>
jQuery返回顶部代码
查看>>
v-charts
查看>>
需要学习的编程语言
查看>>
(十七)jdbc(Java Data Base Connectivity,java数据库连接)基础使用
查看>>
1113: [视频]树形动态规划(TreeDP)8:树(tree)(树形dp状态设计总结)
查看>>
再谈H5存储问题--浏览器无痕模式不支持
查看>>
JS原型与面向对象总结
查看>>
构建之法阅读笔记04
查看>>
Fixed元素在滚动时会抖动----开启硬件加速
查看>>
NodeJs安装步骤与淘宝镜像
查看>>