Netty是什么?
作為Java開發(fā)者,相信大家或多或少都聽說過或者是使用過Netty,而說起Netty,就不得不先說一下IO模型。
IO模型
Unix網(wǎng)絡(luò)編程中定義了五種網(wǎng)絡(luò)模型:
- 阻塞IO
- 非阻塞IO
- IO多路復(fù)用
- 信號(hào)驅(qū)動(dòng)IO
- 異步IO
很多朋友在看到IO、阻塞、非阻塞、同步、異步等字眼的時(shí)候都感到頭大,之前也和同事討論過這個(gè)問題。那么是不是阻塞等于同步,非阻塞等于異步?按照我自己的理解來說:
- 同步、異步:是一種訪問數(shù)據(jù)的方式,同步需要主動(dòng)的進(jìn)行數(shù)據(jù)讀寫,而異步則只需要一個(gè)數(shù)據(jù)讀寫成功的通知,讀寫都由內(nèi)核來完成
- 阻塞、非阻塞:是進(jìn)程在IO過程中是否會(huì)掛起進(jìn)行等待,如果需要等待則是阻塞,否則是非阻塞
從上面的描述上可以看到,凡是異步的IO,就一定是非阻塞的,不存在異步阻塞IO這種IO模型,前四種IO模型全部是同步IO。一次IO操作簡單來說會(huì)經(jīng)歷兩個(gè)階段:
- 等待數(shù)據(jù)準(zhǔn)備完成
- 從內(nèi)核將數(shù)據(jù)拷貝至用戶進(jìn)程中
1.阻塞IO

從圖上可以看到,在阻塞IO模型中用戶進(jìn)程發(fā)起一次IO請(qǐng)求,內(nèi)核需要等待數(shù)據(jù)準(zhǔn)備完成,在數(shù)據(jù)準(zhǔn)備完成后,進(jìn)行數(shù)據(jù)拷貝,拷貝完成后給用戶進(jìn)程返回IO成功。從應(yīng)用角度來看,整個(gè)IO過程直至內(nèi)核返回成功之前,進(jìn)程都處等待操作完成的狀態(tài);而從內(nèi)核角度來看,數(shù)據(jù)準(zhǔn)備階段,需要阻塞等待數(shù)據(jù)準(zhǔn)備完成,數(shù)據(jù)拷貝階段也需要阻塞等待拷貝完成,IO的兩個(gè)階段都被阻塞了,所以這是一種同步阻塞的IO方式。
2.非阻塞IO

阻塞IO工作時(shí),用戶進(jìn)程完全被阻塞住而不能進(jìn)行其他的工作。從圖中可以看出,當(dāng)用戶進(jìn)程發(fā)出read操作時(shí),如果內(nèi)核中的數(shù)據(jù)還沒有準(zhǔn)備好,那么它并不會(huì)阻塞用戶進(jìn)程,而是立刻返回一個(gè)error。從用戶進(jìn)程角度講 ,它發(fā)起一個(gè)read操作后,并不需要等待,而是馬上就得到了一個(gè)結(jié)果。用戶進(jìn)程判斷結(jié)果是一個(gè)error時(shí),它就知道數(shù)據(jù)還沒有準(zhǔn)備好,于是它可以再次發(fā)送read操作。一旦內(nèi)核中的數(shù)據(jù)準(zhǔn)備好了,并且又再次收到了用戶進(jìn)程的system call,那么它馬上就將數(shù)據(jù)拷貝到了用戶內(nèi)存,然后返回。在非阻塞式IO中,用戶進(jìn)程其實(shí)是需要不斷的主動(dòng)詢問內(nèi)核數(shù)據(jù)準(zhǔn)備好了沒有。
3.IO多路復(fù)用

IO多路復(fù)用也會(huì)被人們稱為事件驅(qū)動(dòng)IO。使用select/epoll的好處就在于單個(gè)process就可以同時(shí)處理多個(gè)網(wǎng)絡(luò)連接的IO。它的基本原理就是select/epoll這個(gè)方法會(huì)不斷的輪詢所負(fù)責(zé)的所有socket,當(dāng)某個(gè)socket有數(shù)據(jù)到達(dá)了,就通知用戶進(jìn)程。用戶進(jìn)程收到通知后進(jìn)行數(shù)據(jù)拷貝的系統(tǒng)調(diào)用,這個(gè)階段是從內(nèi)核角度來看阻塞等待數(shù)據(jù)拷貝完成的,所以IO多路復(fù)用也是一種同步的IO模式。
4.異步IO

用戶進(jìn)程發(fā)起read操作之后,立刻就可以開始去做其它的事。而另一方面,從內(nèi)核的角度,當(dāng)它收到一個(gè)異步讀請(qǐng)求之后,首先會(huì)立刻返回,所以不會(huì)對(duì)用戶進(jìn)程產(chǎn)生任何阻塞。然后,內(nèi)核會(huì)等待數(shù)據(jù)準(zhǔn)備完成,然后將數(shù)據(jù)拷貝到用戶內(nèi)存,當(dāng)這一切都完成之后,內(nèi)核會(huì)給用戶進(jìn)程發(fā)送一個(gè)signal,告訴它read操作完成了。整個(gè)過程中都不需要用戶進(jìn)程進(jìn)行主動(dòng)的阻塞數(shù)據(jù)讀寫操作,完全沒有阻塞。用戶進(jìn)程只需要發(fā)起IO請(qǐng)求,然后做其他事,收到IO完成的通知后,直接對(duì)數(shù)據(jù)進(jìn)行操作。