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)){
//server
int cfd = accept(fd, NULL, 0);
maxfd = cfd;
FD_SET(cfd, &readers);
maxfd = maxfd < cfd ? cfd : maxfd;
continue;
}
//client
for(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
本人微信:xiaoshitou5854
linux epoll,poll,select的更多相关文章
- 理解select,poll,epoll实现分析
mark 引用:http://janfan.cn/chinese/2015/01/05/select-poll-impl-inside-the-kernel.html 文章 select()/poll ...
- select,poll,epoll,selectors
一 了解select,poll,epoll IO复用:为了解释这个名词,首先来理解下复用这个概念,复用也就是共用的意思,这样理解还是有些抽象, 为此,咱们来理解下复用在通信领域的使用,在通信领域中为了 ...
- select,poll,epoll
1. Epoll 是何方神圣? Epoll 可是当前在 Linux 下开发大规模并发网络程序的热门人选, Epoll 在 Linux2.6 内核中正式引入,和 select 相似,其实都 I/O 多路 ...
- select,poll,epoll之间的区别
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替.而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替, ...
- Select, Poll,Epoll
Date: 2019-06-19 Author: Sun 1. Select select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当se ...
- [转] Epoll 相对Poll和Select的优点
http://blog.csdn.net/summerhust/article/details/18260117 PS: 相对select来说,Poll的监听列表比select更短,并且Poll的监听 ...
- IO多路复用之select,poll,epoll个人理解
在看这三个东西之前,先从宏观的角度去看一下,他们的上一个范畴(阻塞IO和非阻塞IO和IO多路复用) 阻塞IO:套接口阻塞(connect的过程是阻塞的).套接口都是阻塞的. 应用程序进程-----re ...
- Linux 设备驱动--- Poll 方法 --- Select【转】
转自:http://blog.csdn.net/yikai2009/article/details/8653842 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] Sele ...
- 关于同步,异步,阻塞,非阻塞,IOCP/epoll,select/poll,AIO ,NIO ,BIO的总结
相关资料 IO基本概念 Linux环境 同步异步阻塞非阻塞 同步与异步 阻塞与非阻塞 IO模型Reference Link 阻塞IO模型 非阻塞IO模型 IO复用模型 信号驱动异步IO模型 异步IO模 ...
随机推荐
- [日常] lscpu查看cpu的详细信息
查看自己电脑的cpu的详细信息 root@tao-PC:/home/tao# lscpu Architecture: x86_64 CPU op-mode(s): -bit, -bit Byte Or ...
- 6. Go语言—字符串操作
一.字符串支持的转义字符 \r 回车符(返回行首) \n 换行符(直接跳到下一行的同列位置) \t 制表符 \' 单引号 \" 双引号 \\ 反斜杠 \uXXXX Unicode字符码值转义 ...
- mongodb数据库的存储问题
MongoDB在Windows中默认的数据库目录是c:\data.如果在没有该目录的情况下,直接运行mongod.exe,就会报如下错误(并没有把mongodb设置为服务,所以通过命令行的形式启动,注 ...
- SpringBoot application.properties配置参数详情
multipart multipart.enabled 开启上传支持(默认:true) multipart.file-size-threshold: 大于该值的文件会被写到磁盘上 multipart. ...
- Appium自动化测试之微信h5元素识别和代码实战
总会有人问微信的自动化测试怎么做.其实我不太明白,为啥你要对ta做自动化测试啊,除非你们公司产品是基于微信做的开发否则没必要.即使一个公众号我也觉得没必要做自动化测试,基本功能点下没问题就可以了,毕竟 ...
- 【Ribbon篇四】Ribbon介绍(1)
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具. 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法, ...
- jenkins配置自动部署java程序
任务背景 该项目包含4个程序包:a.jar,b.jar,c.jar,d.jar,每次启动前需要修改程序中的配置文件(修改数据源配置),然后按照先后顺序启动. 任务目标 1.利用jenkins拉取代码, ...
- Harbor + Https 部署
关闭防火墙和selinux systemctl stop firewalld sed -i 's/SELINUX=.*/SELINUX=disabled/g' /etc/sysconfig/selin ...
- Jms规范学习
1.什么是消息中间件? 关注于数据的发送和接受,利用高效可靠的异步消息传递机制集成分布式系统. 2.什么是JMS? Java消息服务(java Message Service)即JMS,是一个java ...
- IIS 503错误解决办法 HTTP Error 503
今天在win7上部署一个IIS网站,莫名出现HTTP Error 503,于是对比了一下之前的网站配置,依然无果. 无奈之下,挨个查看IIS配置.查看“事件查看器”,尝试修改应用程序池 - 高级设置 ...