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