五种IO模型

所有的I/O都分为两步完成,第一步是等待事件的发生,第二步是将数据进行拷贝。

一个高效的I/O模型就是尽量减少等待在整个I/O模型中所占的比重。

阻塞I/O

在内核将数据准备好之前, 系统调⽤用会⼀一直等待. 所有的套接字, 默认都是阻塞⽅方式。
这里写图片描述

非阻塞I/O

这里写图片描述

如果内核还未将数据准备好,系统调用仍然会直接返回,并且返回WOULDBLOCK错误码。非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符, 这个过程称为轮询. 这对CPU来说是较⼤大的浪费, 一般只有特定场景下才使⽤用。这种等待被称为忙等。

通过fcntl(fd, F_SETEL, flag | O_NONBLOCK)函数将套接口设置为非阻塞。

信号驱动I/O

内核将数据准备好的时候,使用SIGIO信号通知应用程序进行IO操作。

这里写图片描述

多路转接

这里写图片描述

这种方式看似和阻塞式IO类似,但事实上最核心在于IO多路转接能够同时等待多个文件描述符的就绪状态,这也是现在使用较多的一种IO方式。

这种I/O操作调用的函数有select、poll和epoll三种实现。

用select来管理多个IO,FD_SETSIZE个,所监听的套接口是有上限的,一旦其中一个IO或者多个IO检测到我们所感兴趣的事件。

select函数返回,返回值为检测到的事件个数。

并且返回哪些IO发生了事件,遍历这些事件,进而处理事件。

int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);

//ndfs表示读、写、异常集合中的文件描述符 的最大值+1
//readfds表示读事件集合,底层实现是一张位图
//writefds表示写事件的集合
//exceptfds表示异常集合
//timeout表示超时时间,NULL表示不会超时,一直等待
void FD_CLR(int fd, fd_set *set);   //将文件描述符fd从集合中移除
int FD_ISSET(int fd, fd_set *set);  //判断fd是否在集合当中
void FD_SET(int fd, fd_set *set);   //将fd添加到集合当中
void FD_ZERO(fd_set* set);      //清空集合

select无法处理多核并行的请求,处理方式,要是想处理则需要多进程/多线程使用select。

异步I/O

由内核在数据拷贝完成时,通知应用程序。

这里写图片描述

读、写、异常事件发生的条件
可读:

  • 套接口缓冲区有数据可读
  • 连接的读一半关闭,即收到FIN段,读操作将返回0
  • 如果为监听套接口,已完成连接队列不为空
  • 套接口上发生了一个错误待处理,错误可通过getsockopt指定SO_ERROR选项来获取

可写:
- 套接口发送缓冲区有空间容纳数据
- 连接的写一半关闭。即收到RST段之后,再次调用write操作(SIGPIPE)
- 套接口上发生了一个错误待处理,错误可通过getsockopt指定SO_ERROR选项

异常:
- 套接口存在带外数据

同步通信与异步通信:

首先,这里谈到的同步是指I/O中的同步与异步,而非进程或线程的同步。

同步和异步关注的是消息通信机制,上面的五种模型中,前四种皆为同步通信。

  • 所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回,但是一旦调用返回,就得到返回值了;也就是说调用者会一直等待调用结果。
  • 异步则相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果;当一个异步过程调用发出后,调用者不会立刻得到结果;而是在调用发出后,被调用者通过状态、通知来通知调用者,或者通过回调函数处理这个调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值