目录
一、基础概念
1.用户空间与内核空间
操作系统核心是内核(kernel),为了保护内核安全,操作系统将虚拟空间划分为内核空间和用户空间。对于Linux 32位操作系统寻址空间(虚拟存储空间)为4G,内核空间与用户空间划分为:
- 内核空间1G:最高的1G字节,虚拟地址0xC0000000~0xFFFFFFFF
- 用户空间3G:最低的3G字节,虚拟地址0x00000000~0xBFFFFFFF
1GB = 1024 MB = 1024 * 1024 KB = 1024 * 1024 * 1024 B= 2^10 * 2^10 * 2^10 B = 2^30 B
4GB = 4 * 2^30 B = 2^32 B
内核空间具有访问底层硬件设备的所有权限,用户进程不能直接操作内核。
2.缓存I/O
又被称为标准I/O,是大多数文件系统的默认I/O。对于Linux,操作系统会将I/O的数据缓存在页缓存(Page cache)中。数据发生两次拷贝:数据->内核空间的页缓存->用户空间。内存映射等方式避免两次拷贝,本文不谈。
二、I/O - 同步、异步、阻塞、非阻塞
根据上节提到的IO数据拷贝过程可知,经历两个阶段:
- wait for data
- copy data from kernel to user
1.阻塞I/O
linux中默认socket都是blocking,用户进程调用recvfrom,该进程会一直被阻塞直到kernel返回结果。
2. 非阻塞I/O
用户进程调用recvfrom不会block等待,如果kernel没准备好数据会返回EWOULDBLOCK错误。因此,非阻塞I/O要一直主动询问,也就是一直调用recvfrom直到返回数据。
3.I/O多路复用
也叫做event driven I/O,这里就会涉及到select\poll\epoll方法。
优势在于单个process可同时处理多个连接的I/O,基本原理就是select/poll/epoll会不断轮询所有socket,当某一个socket有数据了就通知用户进程。
当用户进程调用了select,该进程block,kernel监视所有该select负责的socket,只要有一个socket中有数据ready了select就返回。这时候再recvfrom拷贝数据到用户空间。
4.异步I/O
首先用户进程发起read后,kernel会立即返回不阻塞,虽然不是返回数据。然后kernel一个人抗下了一切,一切完成后给用户进程发送signal告诉它read操作完成了。
三、非阻塞I/O与异步I/O的区别
wait for data阶段,都不阻塞。
copy data from kernel to user阶段,非阻塞I/O是阻塞的,异步I/O全程不阻塞。