好久没用I/O复用了,感觉差点儿相同都快忘完了。记得当初刚学I/O复用的时候花了好多时间。可是因为那会不太爱写博客,导致花非常多时间搞明确的东西,依旧非常easy忘记。俗话说眼过千遍不如手过一遍,的确。在以后的学习中,不管知识的难易亦或是重要程度怎样。我都会尽量义博客的形式记录下来,这样即能用博客来督促自己学习,也能加深对知识的理解俩全其美,好了废话不说了。

I/O复用的基本概述

I/O复用技术主要是用来同一时候监听多个套接字描写叙述符,使得我们的程序大幅度的提高性能,一般例如以下情况会用到I/O复用技术
(1)程序须要同一时候处理多个socket
(2)客户端程序需同一时候处理用户输入和网络连接
(3)TCPserver要同一时候处理监听socket和连接socket
(4)server要同一时候处理TCP和UDP请求
(5)server要同一时候处理多个端口

1.select系统调用

#include<sys/select.h>
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);

.ndf參数指定被监听文件描写叙述符个数,它通常被设为select监听的全部文件描写叙述符加1。
.readfds,writefds,exceptfds參数分别指向可读,可写和异常事件,应用程序通过将自己感兴趣的文件描写叙述符增加到相应的集合中去,select调用返回时。内核将改动他们来通知应用程序哪些文件描写叙述符已经就绪,timeout为超时时间,select调用成功返回就绪的文件描写叙述符个数
我们一般使用例如以下宏来訪问fd_set中的位

#include<sys/select.h>
FD_ZERO(fd_set *fdset);     //清除fdset的全部位
FD_SET(int fd,fd_set *fdset);//设置fdset的fd位
FD_CLR(int fd,fd_set *fdset);//清除fdset的位fd
int FD_ISSET(int fd,fd_set *fdset); //測试fdset的位是否被设置

文件描写叙述符就绪条件
(1)socket内核接收缓冲区大于或等于其低水位标志SO_RCVLOWAT.此时我们能够无堵塞的读该socket
(2)socket通信的对方关闭连接,此时对该socket的读操作将返回0
(3)监听socket上有新的连接请求
(4)socket上有未处理的错误
(5)socket的内核发送缓冲区大于其低水位字节SO_SNDLOWAT
(6)socket使用非堵塞connect连接成功或失败之后
(7)socket上有未处理的错误
详细实例
參考伪代码例如以下

#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/select.h>int main(void)
{if(argc < 3){cout<<"參数有误"<<endl;}char *ip = argv[1];int port = atoi(argv[2]);int ret = 0;struct sockaddr_in address;bzero(&address,sizeof(adddress));address.sin_family = AF_INET;inet_pton(AF_INET,ip,&address.sin_addr);address.sin_port = htons(port);int listenfd = socket(AF_INET,SOCK_STREAM,0);assert(ret != -1);ret = bind(listenfd,(struct sockaddr *)&address,sizeof(address));assert(ret != -1);ret = listen(listenfd,5);assert(ret != -1);struct sockaddr_in client_address;socklen_t len = sizeof(client_address); int connfd = accept(listenfd,(struct sockaddr *)&client_address,&len);if(connfd < 0){cout<<"error"<<endl;close(listenfd);}char buf[1024];fd_set readfds;FD_ZERO(&readfds);while(1){bzero(buf,1024);FD_SET(connfd,&readfds);ret = select(connfd + 1,&readfds,NULL,NULL,NULL);if(ret < 0){cout<<"error"<<endl;}//判读可读事件是否发生if(FD_ISSET(connfd,&readfds)){ret = recv(connfd,buf,sizeof(buf) - 1,0);if(ret <= 0){break;}cout<<buf<<endl;}}close(listenfd);close(connfd);return 0;
}

select的特点
select的内部实现调用了poll(以下会写道,所以读者能够先跳过这里,去读poll,然后在回头一起看这个)。全部它和poll的特点同样。仅仅是函数接口有所不同,本质一样
poll的特点例如以下
(1)将用户传入的pollfd数据(相应select的描写叙述符集合)复制到内核空间,这个拷贝过程事件复杂度为O(N)
(2)挨个查询每个文件描写叙述符的状态,假设无就绪的文件描写叙述符,则进程就会挂起等待,知道发生超时或设备驱动再次唤醒它。然后它再次遍历全部的文件描写叙述符,找出发生事件的文件描写叙述符。因为其共遍历2次文件文件描写叙述符,所以其事件复杂度为O(N)
(3)将获得的数据拷贝至用户空间。时间复杂度又是O(N)

2.poll的使用

poll的原型例如以下

#include<poll.h>
int poll(struct pollfd *fds,nfds_t nfds,int timeout);

当中fds为pollfd类型的结构体数组其结构体定义例如以下

struct pollfd
{int fd;      //要监听文件描写叙述符short events;//注冊的事件short revents;//实际发生的事件,内核填充
}

poll可监听的事件类型例如以下(仅仅列出了经常使用的)

事件 描写叙述
POLLIN 数据可读
POLLOUT 数据可写
POLLRDHUB TCP连接被对方关闭,或对方关闭了写操作
POLLHUB 挂起,比方管道的写端被关闭
POLLERR 错误

nfds为监听的文件描写叙述符个数
timeout为超时事件
索引Poll返回的文件描写叙述符

int ret = poll(fds,MAX_EVENT_NUMBER,-1);//必须遍历全部文件描写叙述符找到当中的就绪事件(也能够依据已知的就绪个数进行简单的优化)for(int i = 0;i<MAX_EVENT_NUMBER,i++)
{if(fds[i].revents & POLLIN){int sock = fds[i];}
}

关于poll的特点读者能够回到select去看,前面有写到,因为实在说其和select的内部实现机制是一样的所以不是必需多余写

3.epoll的使用

epoll是linux特有的I/O复用函数,他在实现和使用上与其它I/O复用有所不同。

它是使用一组函数来完毕任务的,其次epoll把用户关心的文件描写叙述符上的事件放在一个内核事件表中。

epoll须要使用一个额外的文件描写叙述符来来唯一的标识内核中的这个事件表,文件描写叙述符使用epoll_create()来创建

#include<sys/epoll.h>
int epoll_create(int size);

size參数告诉内核事件表须要多大,该函数返回的文件描写叙述符。将用于接下来全部函数的第一个參数

以下函数用来操作内核事件表

#include<sys/epoll.h>
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);

fd为要操作的文件描写叙述符,op參数则指定操作类型,操作类型有例如以下几种

操作类型 详细描写叙述
EPOLL_CTL_ADD 往事件表中注冊fd上的事件
EPOLL_CTL_MOD 改动fd上的注冊事件
EPOLL_CTL_DEL 删除fd上的注冊事件

epoll_event结构体的定义例如以下

struct epoll_event
{_uint32_t events    //epoll事件epoll_data_t        //用户数据
}

当中epoll_data_t是个联合体其定义例如以下

typedef union epoll_data
{void *ptr;int fd;uint32_t u32;uint64_t u64;
}epoll_data_t

epoll_wait()函数
epoll事件调用的主要接口就是epoll_wait函数,它在一段超时事件内等待一组文件描写叙述符上的事件

#include<sys/epoll.h>
int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);

该函数成功时返回就绪的文件描写叙述符个数
假设epoll_wait检測到就绪事件,就将全部的就绪事件赋值到第二个參数epoll_event数组当中,它仅仅用于输出检測到的就绪事件。不想poll的数组參数既用于传入用户注冊的事件,又用于输出内核检測的事件,这会极大的减少应用程序索引文件描写叙述符的效率
epoll的使用

int ret = epoll_wait(epollfd,events,MAX_EVENT_NUMBER,-1);
//仅仅需遍历ret个文件描写叙述符
for(int i = 0;i<ret;i++)
{
int sockfd = events[i].data.fd;
}
特别注意epoll对文件描写叙述符有俩中模式LT和ET。ET是epoll的高效模式

epoll的特点
epoll在内核实现中是依据每个fd上的俄callback函数来实现的,仅仅有活跃的fd才会主动调用callback,其它的fd则不会。

假设所监控的全部文件描写叙述符基本上都是活跃的那么epoll和select或poll差距不是太大。可是要是所监控的文件描写叙述符仅仅有少数活跃,epoll的效率要远高于他俩

转载于:https://www.cnblogs.com/yfceshi/p/7098310.html

linux下select,poll,epoll的使用与重点分析相关推荐

  1. Linux下select, poll和epoll IO模型的详解

    http://blog.csdn.net/tianmohust/article/details/6677985 一).Epoll 介绍 Epoll 可是当前在 Linux 下开发大规模并发网络程序的热 ...

  2. linux中select和epoll原理,Linux下selectpollepoll的实现原理(一)

    最近简单看了一把 linux-3.10.25 kernel中select/poll/epoll这个几个IO事件检测API的实现.此处做一些记录. 其基本的原理是相同的,流程如下 先依次调用fd对应的s ...

  3. linux poll函数 实现,Linux select/poll/epoll 原理(一)实现基础

    本序列涉及的 Linux 源码都是基于 linux-4.14.143 . 1. 文件抽象 与 poll 操作 1.1 文件抽象 在 Linux 内核里,文件是一个抽象,设备是个文件,网络套接字也是个文 ...

  4. Python之路-python(Queue队列、进程、Gevent协程、Select\Poll\Epoll异步IO与事件驱动)

    一.进程: 1.语法 2.进程间通讯 3.进程池 二.Gevent协程 三.Select\Poll\Epoll异步IO与事件驱动 一.进程: 1.语法 1 简单的启动线程语法 2 def run(na ...

  5. python3 异步 非阻塞 IO多路复用 select poll epoll 使用

    有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理还是有必要的. 下面记录下分别基于Select/Poll/Epoll的echo ser ...

  6. select,poll,epoll区别面试常问

    select,poll,epoll区别: select优点 1)select()的可移植性更好,在某些Unix系统上不支持poll() 2)select() 对于超时值提供了更好的精度:微秒,而pol ...

  7. select poll epoll IO操作多路复用及猴子补丁

    一:select(能监控数量有限,不能告诉用户程序具体那个连接有数据) select目前几乎所有的平台都支持,其良好的跨平台支持也是一个优点 select的缺点在于单个进程能够监控的文件描述的数量存在 ...

  8. IO多路复用select/poll/epoll详解以及在Python中的应用

    IO multiplexing(IO多路复用) IO多路复用,有些地方称之为event driven IO(事件驱动IO). 它的好处在于单个进程可以处理多个网络IO请求.select/epoll这两 ...

  9. Python异步非阻塞IO多路复用Select/Poll/Epoll使用

    来源:http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理 ...

最新文章

  1. 酷!一键构建我自己的PHP框架的开发环境
  2. 切换执行等级的命令init
  3. mysql mof_mof提权
  4. svn中“clean up”死循环问题解决办法
  5. 5999元!OPPO Find X5 Pro 8+256GB版今日首销
  6. mysql数据库BigInt数据类型和实体对象中BigInteger,Long类型的冲突
  7. Mac版正式上线剪映,适配用M1
  8. 苹果cmsV10简约白色风格自适应模板
  9. RabbitMQ windows 管理工具
  10. I/O流(万流齐发、万流归宗) 本章目标: 掌握 讲  解:★★★★★ http://kuaibao.qq.com/s/20200527A0LR3000?refer=spider 1.I/O流概
  11. C#获取标准北京时间
  12. 2011广告联盟排名,最好的广告联盟推荐
  13. Android 打印Log语句
  14. 网络分析仪 smith圆图调试
  15. John A·Rogers报告分享
  16. 小白装机工具提示在引导修复时检测到错误解决方法
  17. 如何快递打造直播----概念篇(一)
  18. 计算机信息管理专业自考教材,计算机信息管理自考本科课程
  19. 英语在线发音linux,英语在线读音好处这么多?
  20. 05 python爬虫 (58同城项目)

热门文章

  1. sql 整改措施 注入_记一次Sql注入 解决方案
  2. 盘点七大类当前世界流行的数据挖掘技术
  3. Leetcode-401-二进制手表
  4. 系统学习深度学习(二十八)--DSD
  5. 前景检测算法(十一)--基于LBP纹理
  6. 人脸检测(八)--HOG特征原理及实现
  7. 个人空间html5主页面,2.HTML 教程- (HTML5 简介)
  8. MCU —— 数码管显示笔记
  9. 电路——I/O口定时翻转电平驱动蜂鸣器注意事项
  10. jira状态评审未通过后 不能修改_去年职称申报未通过,今年再报名的,这些变化需要注意了...