一、IO的過程

一次IO請求存在2個階段
階段一:等待數據,即數據從I/O設備到內核內存(操作系統緩沖區)。(I/O設備可能為磁盤, 也可能為網卡)
階段二:復制數據,即數據內核內存到進程內存(應用程序緩沖區)
阻塞/非阻塞,同步/非同步
階段一:阻塞/非阻塞 【DMA Copy】
階段二:同步/非同步 【CPU Copy】
二、I/O模型

(面試題)談談I/O模型?
1、首先I/O請求過程,指的是數據從IO設備拷貝到用戶空間的步驟(兩步,等待數據和復制數據階段)
2、每種IO模型對這兩步的處理不同,像阻塞I/O模型,它對於這兩個階段都是阻塞的 ,非阻塞I/O模型,對於等待數據階段會對一個文件描述符不斷發起檢測,並會立即返回一個結果,如果可以,就阻塞進行復制數據階段,I/O復用模型在等待數據階段會阻塞,來檢查多個文件描述符,不會立即返回結果,只要有一個文件描述符可以工作,就阻塞進行復制數據階段,信號驅動I/O模型在等待數據階段會發送一個信號,並等待通知,然后阻塞完成復制數據階段,異步I/O模型這兩個階段都是非阻塞的。
三、I/O多路復用
I/O多路復用運行進程同時檢查多個文件描述符來找出他們中的任何一個是否可執行I/O操作
三種實現方式:
Select
Poll
Epoll
Select:通過設置或檢查存放fd標志位的數據結構來進行下一步處理
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)

缺點:
1、重復的CPU拷貝:每次調用select,都需要把fd集合從用戶態拷貝到內核態,這個開銷在fd很多時會很大
2、存在無效的遍歷:同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時會很大
3、單線程select支持的文件描述符受限於FD_SETSIZE宏(即c的常量定義),是操作系統定義的,Linux默認是1024
Poll:本質與Select無區別,只是不受FD_SETSIZE宏限制。
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

優點:采用鏈表的方式存儲pollfd,不受FD_SETSIZE限制,只受限於操作系統允許打開的最大文件描述符數目
缺點:
1、每次調用poll,都需要把pollfd鏈表從用戶態拷貝到內核態,這個開銷在fd很多時會很大
2、同時每次調用poll都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時會很大
Epoll:Event Poll,使用一個文件描述符管理多個描述符,將用戶關心的文件描述符事件放入內核到一個事件表中。
int epoll_create(int size):創建epoll文件描述符
size:需要監聽的數目一共有多大。
返回值:一個文件描述符(epfd),用於epoll_ctl、epoll_wait
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event):管理epoll監聽的文件描述符與事件類型
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout):收集在epoll監控的事件中已發生的事件
優點:
1、epoll會在epoll_ctl()中注冊,只需要將所有的fd拷貝到內核事件表一次,不用再每次調用epoll_wait()時重復拷貝
2、epoll只返回就緒的描述符,減少無效的遍歷
3、能支持的fd數量是單個進程最大打開文件數
缺點:編程復雜
(面試題)什么是I/O多路復用?
1、I/O多路復用是I/O請求的一種模型
2、它有三種實現方式,分別是select、poll以及epoll,對於select,它是通過設置和檢查存放fd標志位的數據結果來進行下一步處理,它的缺點是重復的CPU拷貝,存在無效的遍歷、單線程select支持的文件描述符還受限制(宏限制,操作系統定義的),poll利用鏈表來存儲fd集合,使得單線程支持的文件描述符不再受限於宏,但是它的缺點仍然包括重復的CPU拷貝和存在無效的遍歷,而epoll是通過使用一個文件描述符來管理多個文件描述符,將用戶關心的文件描述符事件放入內核事件表,所以不會重復的CPU拷貝,同時它只返回就緒的描述符,不會有無效的遍歷,支持的fd數量是單個進程能打開的最大文件數。
四、Java IO模型
三種IO模型:
1、OIO:Old IO,也可以叫BIO(Blocking-IO),同步阻塞IO
2、NIO:New IO,也可以叫NIO(None-Blocking IO),同步非阻塞IO 【JDK 1.4+】
3、AIO:異步非阻塞IO 【JDK1.7+】
‘
BIO對應 Linux IO模型的阻塞IO
’NIO和AIO對應Linux IO模型的IO多路復用,並且都是使用epoll實現
OIO
1、抽象模型可以分為:流、輸入輸出流、字符字節流,就是InputStream、OutStream、Reader、Writer
2、ServerSocket和Socket程序調用會阻塞,所以也將此類歸結於BIO中。
NIO
1、抽象模型可以分為:Channel管理、Buffer緩沖、Selector選擇器
Channel與Buffer:數據總是從通道讀取到緩沖區中,或者從緩沖區寫入到通道中。

Selector:允許單線程處理多個 Channel
OIO和NIO的區別

NIO的Buffer:一塊可以寫入數據,也可以從中讀取數據的內存對象。

運用到了適配器模式、裝飾器模式
基本屬性:
容量(capacity):緩沖區能夠容納元素的最大數量
上界(limit):緩沖區實際容納元素的數量
位置(position):下一個要被讀寫的元素的數組下標索引

buffer.flip():Buffer讀寫模型的切換 limit設置為position當前的值;postion會被置為0。
Selector:選擇器,多路復用器,能夠檢測一到多個NIO通道,並能夠知曉通道是否為諸如讀寫事件做好准備的組件。
過程:
1、創建Selector
Selector selector = Selector.open();
2、向Slector注冊通道【FileChannel不可以注冊】
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, Selectionkey.感興趣的事件);
3、開始工作,阻塞到至少有一個通道在你注冊的事件上就緒
selector.select()
