說到netty朽砰,不得不提的一個(gè)就是Java NIO拂封。本文主要介紹JAVA NIO涉及到的一些基礎(chǔ)概念以及對(duì)JAVA NIO的開發(fā)過程進(jìn)行簡單介紹。
基本概念
Java NIO,一般稱為非阻塞IO庶柿,它基于多路復(fù)用模型棉胀。它有三個(gè)基本的概念:Channel(通道)法瑟,Buffer(緩沖區(qū)),Selector(多路復(fù)用器)唁奢。
channel 通道
channel是一個(gè)全雙工通道霎挟,不同于的流的地方,它可以同時(shí)用于讀和寫麻掸。因?yàn)樗侨p工的酥夭,可以比流更好地映射底層操作系統(tǒng)的API,它代表了一個(gè)面向流的可監(jiān)聽讀寫事件的socket脊奋。 channel主要分為兩大類采郎,分別是用于網(wǎng)絡(luò)讀寫的SelectableChannel和用于文件讀寫的FileChannel,其中SelectableChannel又提供了兩個(gè)子類狂魔,分別是面向服務(wù)端的ServerSocketChannel和面向SocketChannel蒜埋。
Buffer 緩沖區(qū)
在 Java NIO中,所有的數(shù)據(jù)都是通過緩沖區(qū)進(jìn)行處理的最楷。在讀取的時(shí)候整份,將數(shù)據(jù)讀取到緩沖區(qū)待错;在寫入數(shù)據(jù)時(shí),也是將數(shù)據(jù)寫入到緩沖區(qū)的烈评。最常用是緩沖區(qū)是ByteBuffer火俄。
Selector
Selector是Java NIO中的多路復(fù)用器。 它的主要作用就是提供已經(jīng)就緒的任務(wù)讲冠,Selector會(huì)不斷輪詢注冊在其上的Channel瓜客,如果某個(gè)Channel上有新的連接接入、讀和寫事件竿开,這個(gè)Channel就會(huì)被輪詢出來谱仪,然后通過SelectionKey可以獲取整個(gè)就緒的Channel集合,進(jìn)行后續(xù)的IO操作否彩。
可以將多個(gè)Channel注冊到一個(gè)Selector上疯攒,使用一個(gè)線程處理所有的IO事件,也可以將多個(gè)Channel注冊到多個(gè)Selector實(shí)例上列荔,利用多線程的高性能處理IO事件敬尺。
編程步驟
服務(wù)端
Java NIO提供的API較為繁瑣,此處就不上代碼了贴浙,對(duì)于多路復(fù)用模型砂吞,服務(wù)端和前文中使用python編寫的過程很類似,主要有以下幾點(diǎn):
- 創(chuàng)建一個(gè)負(fù)責(zé)監(jiān)聽新連接的socket
- 通過系統(tǒng)調(diào)用得到一個(gè)處于就緒狀態(tài)的連接集合
- 創(chuàng)建一個(gè)循環(huán)用來輪詢這個(gè)集合
- 判斷事件類型崎溃。如果是Accept呜舒,則創(chuàng)建新的連接并為其注冊事件,如果是讀寫數(shù)據(jù)笨奠,則作讀寫處理
下面是Java NIO服務(wù)端端的序列圖:
- 創(chuàng)建ServerSocketChannel袭蝗,設(shè)置為非阻塞模式
- 設(shè)置ServerSocketChannel參數(shù),綁定監(jiān)聽地址
- 創(chuàng)建一個(gè)線程般婆,用來輪詢多路復(fù)用器Selector
- 將ServerSocketChannel注冊到Selector到腥,監(jiān)聽SelectionKey.Accept事件
- 在循環(huán)中使用Selector.select()獲取就緒狀態(tài)的channel,對(duì)事件類型進(jìn)行判斷:
- 如果是Accept事件蔚袍,則調(diào)用ServerSocketChannel.accept()創(chuàng)建新的客戶端連接乡范,將其設(shè)置成非阻塞模式,并注冊到Selector監(jiān)聽感興趣的操作(read啤咽、write)
- 如果是Read事件晋辆,則需構(gòu)造ByteBuffer對(duì)象,讀取數(shù)據(jù)包
- 如果是Write事件宇整,則繼續(xù)發(fā)送數(shù)據(jù)包
客戶端
- 創(chuàng)建SocketChannel瓶佳,設(shè)置成非阻塞,設(shè)置Tcp參數(shù)
- 連接服務(wù)端鳞青,如果連接成功霸饲,則向selector注冊讀寫事件为朋,進(jìn)行IO操作
- 如果連接失敗,則向selector注冊CONNECT事件厚脉,輪詢處理习寸。
總結(jié)
Java NIO提供的接口使用起來較為復(fù)雜,netty封裝了更為簡單的方法傻工,并且netty自身的線程模型也是實(shí)現(xiàn)更性能的關(guān)鍵霞溪,后面會(huì)做介紹。