什么是IO?什么是高效的IO?
read/recv
1.没有数据,就会阻塞住(等待缓冲区资源就绪)
2.有数据,read/recv拷贝完成后进行返回
IO = 等+数据拷贝
高效的IO:减少等待的比重
有哪些IO的方式?这么多的方式,有哪些是高效的?
阻塞式IO: 一直等待,没有数据就挂起。
非阻塞式IO:一直等待,如果有数据就接受,没有数据就做自己的事情,查询有没有数据到来。
信号驱动式IO:SIGNAL信号,如果有数据,信号提醒。回调的方式,你好了你来叫我。
多路转接/多路复用:
异步IO:进程将任务交给操作系统。
对比:
阻塞式IO,非阻塞式IO,信号驱动式IO效率上是没有差别的。整体上,非阻塞式IO,信号驱动式可以做其他事情。
信号驱动有没有等待呢?等待了。
阻塞式IO,非阻塞式IO,信号驱动式IO,多路转接/多路复用每个人都等了,都参与了IO过程——同步IO。异步IO并没有参与读取IO的过程。
阻塞式和非阻塞式IO的差别?
共同:都要数据拷贝
不同:等的方式不一样
select:IO = 等 + 拷贝
select只负责等待,可以一次等待多个fd,select本身没有数据拷贝的能力,拷贝要read,write来完成。
1.了解select基本概念和接口介绍
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
参数解析:
int nfds:select要监视多个fd中值最大的fd+1
剩下的四个全部是输入输出型参数:
select关心的事件,只有三类:a.读 b.写 c.异常
fd_set *readfds, fd_set *writefds,fd_set *exceptfds:
fd_set:位图结构,用来表示文件描述符集合
fd_set *readfds:
输入:表示用户告诉内核,你要帮我关心一下,我给你的集合中的所有fd的读事件---哪些fd上的读事件你要关心。比特位的位置,表示fd的数值,比特位的内容,表示是否关心。
输出:内核告诉用户,你所关心的多个fd中,有哪些已经就绪了。比特位的位置,表示fd的数值,比特位的内容,表示是否就绪。
让用户和内核之间互相沟通,互相知晓对方要的和关心的。
struct timeval *timeout:等待方式
- nullptr->阻塞式等待
- struct timeval timeout={0,0};非阻塞
- struct timeval timeout={5,0};5s以内阻塞式,超过5s,非阻塞返回一次
返回值:
- ret>0:有几个fd就绪了
- ret==0:超时返回
- ret<0:select调用失败
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
select特点:
1.select能同时等待的文件fd是有上限的,除非重新改内核,否则无法解决。
2.必须借助第三方数组,来维护合法的fd
3.select的大部分参数是输入输出型的,调用select前要重新设置所有fd,调用之后,我们还要检查更新所有的fd,这带来的就是遍历的成本--用户
4.select为什么第一个参数是最大fd+1呢? 确定遍历范围-内核层面
5.select采用位图,用户->内核,内核->用户,来回的进行数据拷贝。拷贝成本的问题。
EPOLL
poll也是一种linux中的多路转接的方案。
1.select的fd有上限的问题。
2.每次调用都要重新设置关心的fd。
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd *fds:结构体数组
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */请求事件
short revents; /* returned events */就绪事件
};输入看fd+events
输出时fd+revents
nfds_t nfds:数组长度
int timeout:时间单位毫秒
- >0:在timeout以内阻塞,否则每隔一段时间返回
- =0:非阻塞等待
- <0:阻塞等待
返回值:
- ret>0:有几个fd就绪了
- ret==0:超时返回
- ret<0:poll调用失败
EPOLL
1.快速的认识epoll的接口
#include <sys/epoll.h>
int epoll_create(int size);
创建一个epoll模型
用户->内核
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
op:增,删,改
内核->用户int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
struct epoll_event *events,int maxevents:输出型参数