Linux内核将所有外部设备都看作一个文件来操作,而对一个一个文件的读写操作会调用内核提供的系统命令,
返回一个file descriptor(即fd,文件描述符)。
描述符是一个数字,它指向内核中的一个结构体(文件路径、数据区等属性)
因此对socket的读写操作,会返回一个socketfd(socket描述符)
Unix提供5种I/O模型
1. 阻塞I/O模型:默认条件下,所有文件操作都是阻塞的。
以socket为例,在进程中调用recvfrom,直到数据包到达并且复制到应用的缓冲区或者报错,
recvfrom函数才会返回,否则会一直等待。
进程在调用recvfrom时,从开始到返回结果整段时间进程都是阻塞的,一直等待干不了别的。
2.非阻塞I/O模型:对内核缓冲区进行轮询,直到有数据。
调用recvfrom从应用层到内核时,若缓冲区没有数据,就直接返回一个EWOULDBLOCK错误,
并且一般都对非阻塞I/O模型进行轮询检查这个状态,查看内核缓冲区中数据来了没。
3.I/O复用模型:基于Linux的select/epoll,扫描fd是否就绪。
Linux提供 select/epoll(epoll是基于事件驱动,即fd就绪将就立刻返回,而poll是顺序扫描),
进程将一个或多个fd传递给select或epoll系统调用,并阻塞在select操作上,这样select/epoll
就可以帮我们侦测多个fd是否就绪,即是否这个fd有数据。就绪时立刻回调函数rollback。
4.信号驱动I/O模型:使用信号来通知进程数据已就绪,不用阻塞进程。
1.先开启套接口信号驱动I/O功能
2.并通过系统调用sigaction执行一个信号处理函数(该系统调用立刻返回,非阻塞)
3.当数据准备就绪,为该进程生成一个SIGIO信号,通过信号通知进程调用recvfrom函数。
5.异步I/O:通知内核将整个流程完成后通知进程。
1.告知内核启动某个操作,并让内核将整个操作完成(包括将数据从内核复制到用户自己的缓冲区),再通知进程。
2.与信号驱动I/O模型对比:
信号驱动是由内核通知进程何时开始I/O操作;
异步I/O是由内核通知进程何时完成I/O操作;