Netty是什么?
作為Java開發者,相信大家或多或少都聽說過或者是使用過Netty,而說起Netty,就不得不先說一下IO模型。
IO模型
Unix網絡編程中定義了五種網絡模型:
- 阻塞IO
- 非阻塞IO
- IO多路復用
- 信號驅動IO
- 異步IO
很多朋友在看到IO、阻塞、非阻塞、同步、異步等字眼的時候都感到頭大,之前也和同事討論過這個問題。那么是不是阻塞等于同步,非阻塞等于異步?按照我自己的理解來說:
- 同步、異步:是一種訪問數據的方式,同步需要主動的進行數據讀寫,而異步則只需要一個數據讀寫成功的通知,讀寫都由內核來完成
- 阻塞、非阻塞:是進程在IO過程中是否會掛起進行等待,如果需要等待則是阻塞,否則是非阻塞
從上面的描述上可以看到,凡是異步的IO,就一定是非阻塞的,不存在異步阻塞IO這種IO模型,前四種IO模型全部是同步IO。一次IO操作簡單來說會經歷兩個階段:
- 等待數據準備完成
- 從內核將數據拷貝至用戶進程中
1.阻塞IO
從圖上可以看到,在阻塞IO模型中用戶進程發起一次IO請求,內核需要等待數據準備完成,在數據準備完成后,進行數據拷貝,拷貝完成后給用戶進程返回IO成功。從應用角度來看,整個IO過程直至內核返回成功之前,進程都處等待操作完成的狀態;而從內核角度來看,數據準備階段,需要阻塞等待數據準備完成,數據拷貝階段也需要阻塞等待拷貝完成,IO的兩個階段都被阻塞了,所以這是一種同步阻塞的IO方式。
2.非阻塞IO
阻塞IO工作時,用戶進程完全被阻塞住而不能進行其他的工作。從圖中可以看出,當用戶進程發出read操作時,如果內核中的數據還沒有準備好,那么它并不會阻塞用戶進程,而是立刻返回一個error。從用戶進程角度講 ,它發起一個read操作后,并不需要等待,而是馬上就得到了一個結果。用戶進程判斷結果是一個error時,它就知道數據還沒有準備好,于是它可以再次發送read操作。一旦內核中的數據準備好了,并且又再次收到了用戶進程的system call,那么它馬上就將數據拷貝到了用戶內存,然后返回。在非阻塞式IO中,用戶進程其實是需要不斷的主動詢問內核數據準備好了沒有。
3.IO多路復用
IO多路復用也會被人們稱為事件驅動IO。使用select/epoll的好處就在于單個process就可以同時處理多個網絡連接的IO。它的基本原理就是select/epoll這個方法會不斷的輪詢所負責的所有socket,當某個socket有數據到達了,就通知用戶進程。用戶進程收到通知后進行數據拷貝的系統調用,這個階段是從內核角度來看阻塞等待數據拷貝完成的,所以IO多路復用也是一種同步的IO模式。
4.異步IO
用戶進程發起read操作之后,立刻就可以開始去做其它的事。而另一方面,從內核的角度,當它收到一個異步讀請求之后,首先會立刻返回,所以不會對用戶進程產生任何阻塞。然后,內核會等待數據準備完成,然后將數據拷貝到用戶內存,當這一切都完成之后,內核會給用戶進程發送一個signal,告訴它read操作完成了。整個過程中都不需要用戶進程進行主動的阻塞數據讀寫操作,完全沒有阻塞。用戶進程只需要發起IO請求,然后做其他事,收到IO完成的通知后,直接對數據進行操作。