linux epoll,poll,select

epoll函数用法,还有点poll和select

1,LT的epoll是select和poll函数的改进版。

特点是,读完缓冲区后,如果缓冲区还有内容的话,epoll_wait函数还会返回,直到把缓冲区全部读完。

2,ET的epoll(阻塞)

特点是,读完缓冲区后,不管缓冲区还有没有内容,epoll_wait函数都不会再返回,直到对端再一次发送信息过来。估计有的读者朋友会想到用while去读,但是有个致命的问题,因为文件描述符是阻塞的,所以当全部读完后,进程就会阻塞在recv函数那里,就不能够再处理别的连接了。

3,ET的epoll(非阻塞),效率最高的使用方法。

特点是,读完缓冲区后,不管缓冲区还有没有内容,epoll_wait函数都不会再返回,直到对端再一次发送信息过来。但是可以事先用fcntl把文件描述符设置成非阻塞的方式,让后用while一直去读,当全部读完后,recv函数也不会阻塞。

ET的epoll(非阻塞)的例子:

#include <stdio.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>int main(int argc, char** argv){int port = atoi(argv[1]);int lfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = INADDR_ANY;bind(lfd, (struct sockaddr*)&addr, sizeof(addr));listen(lfd, 5);int efd = epoll_create(10);struct epoll_event re;re.events = EPOLLIN;re.data.fd = lfd;epoll_ctl(efd, EPOLL_CTL_ADD, lfd, &re);struct epoll_event events[100];while(1){int ret = epoll_wait(efd, events, 100, -1);printf("======================wait=======\n");if(ret == -1){perror("epoll_wait");exit(1);}for(int i = 0; i < ret; ++i){if(events[i].data.fd == lfd){int cfd = accept(lfd, NULL, NULL);int flags = fcntl(cfd, F_GETFL);flags |= O_NONBLOCK;fcntl(cfd, F_SETFL, flags);struct epoll_event re;re.events = EPOLLIN | EPOLLET;re.data.fd = cfd;epoll_ctl(efd, EPOLL_CTL_ADD, cfd, &re);break;}char buf[3];int ret;while((ret = recv(events[i].data.fd, buf, sizeof buf, 0)) > 0){write(STDOUT_FILENO, buf, ret);}if(ret == 0){epoll_ctl(efd, EPOLL_CTL_DEL, events[i].data.fd, NULL);close(events[i].data.fd);printf("client disconnet\n");}else if(ret == -1 && errno == EAGAIN){printf("read over\n");  }}}
}

poll函数例子:

#include <stdio.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc, char** argv){int port = atoi(argv[1]);int lfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = INADDR_ANY;bind(lfd, (struct sockaddr*)&addr, sizeof(addr));listen(lfd, 5);struct pollfd pfd[1024];for(int i = 0; i < 1024; ++i){pfd[i].fd = -1;}pfd[0].fd = lfd;pfd[0].events = POLLIN;nfds_t maxfd = 0;while(1){int ret = poll(pfd, maxfd + 1, -1);printf("--------------poll------\n");if(pfd[0].revents & POLLIN){int cfd = accept(lfd, NULL, NULL);for(int i = 0; i < 1024; ++i){if(pfd[i].fd == -1){pfd[i].fd = cfd;pfd[i].events = POLLIN;maxfd++;break;}}continue;}for(int i = 0; i <= maxfd; ++i){if(pfd[i].revents & POLLIN){char buf[64];int ret = recv(pfd[i].fd, buf, sizeof buf, 0);if(ret == 0){pfd[i].fd = -1;close(pfd[i].fd);printf("client is disconnet\n");}else{write(STDOUT_FILENO, buf, ret);}}} }
}

通过对比epoll和poll的例子可以看出来:

  • epoll不需要事先决定数组的大小。poll需要。
  • epoll内部是用红黑树实现的效率,不会随着连接的增多,而明显的变低。poll是用链表实现的,所以性能随着连接的增多而降低。poll还不能在windows下使用。epoll是跨平台的。
  • 顺便说下,select是用数组实现的,数组的大小由内核代码写死了,就是1024,所以想增大,只能重新编译内核。但是select是在跨平台的。

关于EPOLLOUT的补足:内核检查写的缓冲区,如果写缓冲区未满,处于可写的状态,epoll_wait函数就会返回。否则阻塞。

  • 水平模式:如果写缓冲区未满,epoll_wait会一直返回。
  • 边缘模式:epoll_wait会先返回一次;然后,写缓冲区从满的状态变成了未满的状态,epoll_wait返回。
    -注意点:调用send等函数的时候,如果写缓冲区满了的话,套接字如果是阻塞的,程序就费了,不再能相应任何事件。如果是非阻塞的话,send就会失败,有些数据就丢失了。所以,正确的做法是,当监听到EPOLLIN事件的时候,把数据读出来后,不要直接调用send等函数,要:把当前节点从树上删掉,然后加入一个EPOLLOUT的节点上去,等待epoll_wait的下一次返回,epoll_wait返回了,说明肯定可写。

select函数例子

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <unistd.h>int main(){int fd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_addr.s_addr = INADDR_ANY;addr.sin_port = htons(12345);bind(fd, (struct sockaddr*)&addr, sizeof(addr));listen(fd, 5);fd_set readers, temp;FD_ZERO(&readers);FD_ZERO(&temp);FD_SET(fd, &readers);int maxfd = fd;int selret = 0;char rbuf[1024] = {0};while(1){temp = readers;selret = select(maxfd + 1, &temp, NULL, NULL, NULL); if(FD_ISSET(fd, &temp)){//serverint cfd = accept(fd, NULL, 0);maxfd = cfd;FD_SET(cfd, &readers);maxfd = maxfd < cfd ? cfd : maxfd;continue;}//clientfor(int i = fd + 1; i <= maxfd; ++i){if(FD_ISSET(i, &temp)){int ret = read(i, rbuf, sizeof(rbuf));printf("recv:%s\n", rbuf);if(ret == 0){FD_CLR(i, &readers);}ret = write(i, rbuf, sizeof(rbuf));}}}}

c/c++ 学习互助QQ群:877684253

1414315-20181106214320230-961379709.jpg

本人微信:xiaoshitou5854

转载于:https://www.cnblogs.com/xiaoshiwang/p/11110204.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362181.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

λ和副作用

总览 Java 8添加了诸如lambda和类型推断之类的功能。 这使语言不那么冗长和简洁&#xff0c;但是它带来了更多的副作用&#xff0c;因为您不必对所做的事情那么明确。 Lambda的返回类型很重要 Java 8推断闭包的类型。 一种方法是查看返回类型&#xff08;或是否返回任何内容&a…

sessionStorage和localStorage的用法,不同点和相同点

一&#xff0c;共同点 &#xff08;1)存储时用setItem: localStorage.setItem("key","value");//以“key”为名称存储一个值“value”sessionStorage.setItem("key", "value"); &#xff08;2&#xff09;获取时用getItem: localS…

shell学习笔记1-文件安全与权限

1&#xff0c;创建文件的用户和他所属的组拥有该文件&#xff0c;文件的属主可以设定谁具有读、写、执行该文件的权限&#xff0c;根用户可以改变任何普通用户的设置。 2&#xff0c;一个文件一经创建&#xff0c;就具有三种访问权限&#xff1a;读&#xff08;可以显示该文件的…

没有IF-ELSE的工厂

面向对象语言具有非常强大的多态性功能&#xff0c;用于删除代码中的if / else或切换大小写。 没有条件的代码易于阅读。 在某些地方必须放置它们&#xff0c;其中一个示例是Factory / ServiceProvider类。 我敢肯定&#xff0c;您已经看到IF-ELSEIF的工厂课程了&#xff0c;…

最新70佳单页网站设计案例欣赏(上篇)

单页网站是指只有一个页面的网站&#xff0c;这种形式的网站曾经非常流行&#xff0c;现在依然有很多人喜欢。不过&#xff0c;并不是每个网站都适合做成单页&#xff0c;一般都是内容比较少而且将来内容也不怎么增加的情况才适合这样做。如果你打算做一个这样的网站&#xff0…

浏览器劫持者

launchpage 浏览器劫持者&#xff0c;它会在未经你的许可下就接管你的浏览器。更多 https://launchpage.org/?uidqT5KGGjMhxpsXWEzIkWR44y5McmHTuSG50ukahoC8gOClKIGNwZP0nuyPBoYUFiBINK7 https://ns.freedrive.cn/?sEB5805AD0&ghttp://item.jd.com/13300636764.html 更…

Kubernetes 中文文档

Kubernetes 中文文档 如果想学习 Kubernetes 的小伙伴&#xff0c;可以参考如下文档学习&#xff1a; https://www.kubernetes.org.cn/docs 文档中详细讲解了 k8s 的设计理念&#xff0c;基本概念&#xff0c;常用命令等。 转载于:https://www.cnblogs.com/miracle-luna/p/1111…

Edge 浏览器

Edge浏览器设计理念 无法播放&#xff1a;https://edgewelcomecdn.microsoft.com/site/images/tabs/rs3/tabs_screen.acd367a2.mp4 控制台消息 WEBGL11256: 检测到 GPU 重置。正在临时切换到软件呈现 WEBGL11056: 遇到的错误太多&#xff0c;将不再记录更多错误 Intersecti…

为什么NULL是错误的?

Java中NULL用法的简单示例&#xff1a; public Employee getByName(String name) {int id database.find(name);if (id 0) {return null;}return new Employee(id); }这种方法有什么问题&#xff1f; 它可能返回NULL而不是对象-这是错误的。 在面向对象的范例中&#xff0c…

网易原来也是个骗子

当初开通photo.163.com网易相册时&#xff0c;就是看着网易的宣传口号&#xff1a;免费而且不限容量&#xff01;结果现在坏了&#xff0c;规则说改就改&#xff0c;容量一下子收到1G&#xff0c;超过部份要么给钱&#xffe5;&#xffe5;&#xffe5;&#xffe5;&#xffe5…

不同设备屏幕尺寸和DPR适配

为什么需要适配 目前市面上设备屏幕属性十分多样化&#xff08;宽度和DPR并不一致&#xff09;&#xff0c;而作为设计和前端开发&#xff0c;无法为每个尺寸的设备单独设计一套UI并将其转为前端代码&#xff0c;这不现实。所以我们需要一套方案来将一套设计稿完美呈现在不同尺…

Test 6.29 T3 小学生

问题描述 “不错,不错!那么,准备好迎接下一道题了么?”一道白光闪过,CJK 眼前出现了 1e100 个小学生。“他们中,有一些人轨了我的机子。现在,我需要你在 1S 之内找出他们,并让他们认错!”凭借自己无所不知的神(xuan)奇(xue)力量, CJK 立刻发现了轨了 JesseLiun的机子的那 n 个…

web安全之CSRF

CSRF是什么 CSRF&#xff08;Cross Site Request Forgery&#xff09;跨站请求伪造&#xff0c;是一种攻击方式。通过名字可以看出这个攻击通常是在其他网站发出的&#xff0c;并不是在目标网站。 该攻击会在用户不知情的情况下盗用用户的登录信息请求目标网站完成对目标网站…

AssertJ Fest Hamcrest

我以前曾在博客中介绍过Hamcrest &#xff0c;并使用其assertThat方法优先于JUnit的Assert 。 但是&#xff0c;我很快发现了FEST断言 &#xff0c;并愉快地切换到它。 它提供了与Hamcrest相同的改进的测试可读性&#xff0c;并改善了故障消息&#xff0c;但具有启用IDE自动完…

Edge浏览器开发人员工具

UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240" 本地存储/会话存储模拟达到上限 资源终于全部列表出来了 删除 Cookie 和 删除会话 Cookie 样式可以实时编辑了 …

作为入门开发者应该知道的事

前言 如果你是开始学习编程并且决心学好&#xff0c;或者你刚离开学校还没有工作&#xff0c;这篇文章刚好适合你 我将分享作为开发者在工作过程中积累的关键点和隐藏的真相 编程是件困难的事&#xff0c;不仅仅对你而言 没有人说过编程是简单的事情&#xff0c;如果是的话&…

linux 第一个内核模块Hello World

内核模块是Linux内核向外部提供的一个插口&#xff0c;其全称为动态可加载内核模块&#xff08;Loadable Kernel Module&#xff0c;LKM&#xff09;&#xff0c;我们简称为模块。Linux内核之所以提供模块机制&#xff0c;是因为它本身是一个单内核&#xff08;monolithic kern…

懒惰和贪婪-正则回溯

需要一定的正则基础&#xff0c;并且是基于JS写的文章。 正则表达式是从左往右匹配的。在使用正则表达式的时候我们知道/.*/可以匹配一个字字符串中所有的字符&#xff0c;/.*?/却一个字符都匹配不到。/(.*)\d/中的.\*可以匹配除了最后一位数字的所有字符&#xff0c;但是之前…

简单的Java SSH客户端

可以使用jcabi-ssh在Java中通过几行代码通过SSH执行shell命令&#xff1a; String hello new Shell.Plain(new SSH("ssh.example.com", 22,"yegor", "-----BEGIN RSA PRIVATE KEY-----...") ).exec("echo Hello, world!");jcabi-ssh…

【JS复习笔记】00 序

作为一个前端苦手&#xff0c;说是复习&#xff0c;你就当我是重学好了。 好吧&#xff0c;我当然不可能抱着一个砖头去复习&#xff0c;所以捡了本薄的来读——《JavaScript语言精粹》。 当初带我的人说这本书挺好&#xff0c;就看这本书好了。我觉得他说的挺对。我喜欢这么…