五种I/0模型
阻塞IO
- 用户空间执行
recv
是阻塞的,一直等到数据到来,拷贝到用户空间的缓冲区buf
- 一旦执行读操作,对方就是阻塞的
非阻塞IO
- 用函数
fcntl(fd,F_SETFL,flag|0_NONBLOCK)
设置成非阻塞 - 没有数据的话返回
EMOULDBLOCK
错误为-1.数据没到来的时候需要持续循环接收,对cpu浪费,称为忙等待,一直等到数据到来
IO复用模式
- 用
select
控制多个文件描述符,阻塞位置提前到了select
,检测到事件便不再阻塞
信号驱动IO
- 建立
SIGIO
信号处理程序 - 一旦有数据到来,就提示给
SIGIO
信号处理程序,递交SIGIO
信号 - 信号是异步处理的一种方式
异步IO
-
用
aio_read
函数实现,提交请求,递交一个应用进程的缓冲区buf
,即使内核没有数据到来,也会返回 -
一旦返回,应用进程可以处理其他事情,异步处理
-
有数据到来,会自动拷贝到应用进程缓冲区,拷贝结束,会递交
aio_read
指定信号,可以为SIGIO
。一旦获得信号,已经拷贝结束了。 -
用户空间没必要用
recv
了,直接从内核推到应用进程
select
-
函数
int select(int nfds,fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
-
select
管理多个文件描述符,也就是IO。一旦IO检测到感兴趣的事件,就会把他们放到集合,并处理,select
返回检测到的个数,并返回哪些IO发生了事件 -
遍历这些事件,进而处理事件
-
举例:没法同时处理键盘输入和网络处理,所以用
select
-
参数说明
readfds
有数据可读集合,一旦有可读集合,就返回
-
writefds
有数据可写集合。。。。。
-
exceptfds
异常集合。。。。
-
timeval
一定要检测到某个时间才能返回,超时事件,在超时内检测到就返回,超时后没检测到也返回
-
nfds
表示读、写、异常集合中的文件描述符的最大值+1
-
他们都是输入输出参数
-
3,4,5 ——> 3, 5 :
readfd
从3,4,5变为3,5 -
isset
判断是否在集合中 -
int fd_stdin =filno(stdin)
转化为文件描述符,file number -
fd set rset
-
FD_isset
宏判断是否存在 -
FD_SET(fd_stdin,&rset)
插入集合的宏 -
单进程处理IO比较方便