王少輝++陳曉鵬
摘 要傳統(tǒng)的BIO技術(shù)在網(wǎng)絡(luò)通信中需要服務(wù)器為每一個(gè)鏈接都建立一個(gè)線程,如果其中已連接的請(qǐng)求沒有任何操作,將造成線程浪費(fèi)。本文分析了BIO技術(shù)、NIO技術(shù)、AIO技術(shù)在網(wǎng)絡(luò)通信中的應(yīng)用場(chǎng)合,解決了傳統(tǒng)BIO技術(shù)的不足,給出了其基本實(shí)現(xiàn)步驟及應(yīng)用場(chǎng)景。
【關(guān)鍵詞】I/O NIO BIO SOCKET通信 Java 多線程
1 引言
傳統(tǒng)BIO技術(shù)在Socket通信中,系統(tǒng)需要為每一個(gè)鏈接建立一個(gè)線程去處理其請(qǐng)求,隨著客戶端的并發(fā)量不斷增加后,會(huì)導(dǎo)致線程數(shù)量的增加嚴(yán)重影響系統(tǒng)的性能。由于并發(fā)量的增加有可能導(dǎo)致服務(wù)器宕機(jī),嚴(yán)重影響到用戶在使用過(guò)程中的良好體驗(yàn)。為解決傳統(tǒng)BIO的不足,Java 中提供了新的API----NIO和NIO2來(lái)解決由于BIO技術(shù)帶來(lái)的系統(tǒng)瓶頸問(wèn)題。在NIO中系統(tǒng)不再為每一個(gè)用戶請(qǐng)求注冊(cè)一個(gè)線程,而是通過(guò)通道將每一個(gè)鏈接都注冊(cè)到多路復(fù)用器上,通過(guò)多路復(fù)用器對(duì)注冊(cè)在其上的鏈接進(jìn)行輪詢檢查,發(fā)現(xiàn)有鏈接請(qǐng)求才會(huì)開啟線程對(duì)其進(jìn)行處理。NIO只在有連接請(qǐng)求時(shí)selector才會(huì)不斷輪詢檢查通道IO操作是否完成,與NIO技術(shù)不同的是AIO技術(shù)是異非步阻塞的。AIO中不再需要多路復(fù)用器,而是由異步非阻塞通道直接操作read和write方法。在客戶端讀寫請(qǐng)求發(fā)出后不再等待服務(wù)器的響應(yīng),而是處理完成后由操作系統(tǒng)來(lái)通知應(yīng)用程序。AIO與NIO這兩種技術(shù)都極大地改變了傳統(tǒng)I/O流的不足。
2 Socket基本通信原理介紹
Socket是網(wǎng)絡(luò)通信中的其中一方,用來(lái)接收網(wǎng)絡(luò)通信中雙方其中一方的請(qǐng)求,方便的對(duì)雙方的數(shù)據(jù)進(jìn)行傳輸。Socket通信分有連接的和無(wú)連接,面向連接的Socket通信與面向非連接的Socket通信相比有更高的可靠性和更有效的數(shù)據(jù)傳輸。本文基于有連接的套接字傳輸。
3 BIO、NIO、AIO技術(shù)比較
3.1 BIO技術(shù)簡(jiǎn)介
BIO技術(shù)同步并且阻塞,在這種情況下,服務(wù)器需要為每一個(gè)連接開啟一個(gè)線程,只要有客戶端有請(qǐng)求服務(wù)器就需要開啟線程去進(jìn)行處理。從客戶端傳來(lái)的每個(gè)請(qǐng)求,服務(wù)器都需要為其創(chuàng)建相應(yīng)的線程去處理其請(qǐng)求。在BIO中,由于其線程的開銷很大,適合于運(yùn)用在并發(fā)量小的場(chǎng)景下。其基本模型如圖1所示。
BIO網(wǎng)絡(luò)通信基本步驟:
3.1.1 服務(wù)低端
(1)創(chuàng)建ServerSocket并綁定監(jiān)聽端口;
(2)創(chuàng)建Socket用來(lái)接收客戶端請(qǐng)求;
(3)創(chuàng)建輸入輸出流用來(lái)接收客戶端輸入或向客戶端輸出數(shù)據(jù);
(4)關(guān)閉輸入輸出流等系統(tǒng)資源。
3.1.2 客戶端
(1)創(chuàng)建Socket綁定IP地址及端口;
(2)創(chuàng)建輸入輸出流用來(lái)接收服務(wù)器端相應(yīng)或向服務(wù)器端發(fā)送數(shù)據(jù);
(3)關(guān)閉輸入輸出流等系統(tǒng)資源。
3.2 NIO技術(shù)簡(jiǎn)介
NIO技術(shù)即New IO技術(shù),NIO技術(shù)由很多類和組件構(gòu)成,其最重要的由channel、Buffer、和Selectors三個(gè)核心部分組成。
Channel:Java NIO中的通道類似于流,但又不完全相同。既可以從通道中讀取數(shù)據(jù)到Buffer也可以將數(shù)據(jù)從Buffer寫入通道中。其中SocketChannel和ServerSocketChannel是NIO中提供的用來(lái)解決Socket通信中的服務(wù)器性能問(wèn)題的。SocketChannel通過(guò)TCP協(xié)議來(lái)讀取網(wǎng)絡(luò)中的數(shù)據(jù),ServerSocketChannel用來(lái)接收鏈接來(lái)的請(qǐng)求以供服務(wù)器相應(yīng)。
Buffer:Buffer是用來(lái)為數(shù)據(jù)提供緩沖區(qū)的。在NIO技術(shù)中,所有的數(shù)據(jù)都必須經(jīng)過(guò)緩沖區(qū)。緩沖區(qū)本質(zhì)上為一塊可讀可寫的內(nèi)存塊,NIO中提供了不同數(shù)據(jù)類型的緩沖區(qū)來(lái)處理不同的數(shù)據(jù)請(qǐng)求,和一些基本的方法來(lái)操作緩沖區(qū)中的數(shù)據(jù)。
Selector:Selector是單線程來(lái)處理多個(gè)鏈接請(qǐng)求的關(guān)鍵。在Socket通信中,如果將多個(gè)鏈接請(qǐng)求注冊(cè)到多路復(fù)用器上,就可以用一個(gè)線程來(lái)處理多個(gè)鏈接請(qǐng)求,這樣就提高了Socket通信的效率。NIO通信中的網(wǎng)絡(luò)模型
如圖2所示。
NIO通信基本步驟:
3.2.1 服務(wù)器端
(1)創(chuàng)建多路復(fù)用器Selector 用來(lái)選擇通道;
(2)創(chuàng)建服務(wù)器端通道ServerSocketChannel;
(3)為多路復(fù)用器上注冊(cè)ServerSocketChannel用來(lái)將數(shù)據(jù)通過(guò)通道讀寫;
(4)申請(qǐng)Buffer存儲(chǔ)數(shù)據(jù);
(5)多路選擇器通過(guò)其key值輪詢檢查通道讀寫B(tài)uffer中的數(shù)據(jù)完成其通信過(guò)程。
3.2.2 客戶端
(1)創(chuàng)建IP地址和端口號(hào)對(duì)應(yīng)的SocketChannel ;
(2)將SocketChannel設(shè)置為非阻塞模式;
(3)創(chuàng)建多路復(fù)用器Selector注冊(cè)SocketChannel到多路選擇器;
(4)多路選擇器輪詢檢查通道從Buffer中讀寫數(shù)據(jù)。
在NIO網(wǎng)絡(luò)通信模型中,客戶端向服務(wù)器端發(fā)起鏈接請(qǐng)求,客戶端將數(shù)據(jù)寫入服務(wù)器端Buffer中,然后通過(guò)channel來(lái)從Buffer讀取數(shù)據(jù)或向Buffer寫入數(shù)據(jù),對(duì)于通道中的數(shù)據(jù)必須經(jīng)過(guò)選擇器來(lái)向服務(wù)器端的線程發(fā)起請(qǐng)求。而每一個(gè)多路選擇器對(duì)應(yīng)一個(gè)線程模型,這樣一來(lái),只有當(dāng)鏈接請(qǐng)求有效時(shí)服務(wù)器才為客戶端開啟線程處理數(shù)據(jù)。對(duì)于同步阻塞的NIO模型中客戶端在向服務(wù)器端發(fā)送完數(shù)據(jù)后會(huì)不斷詢問(wèn)I/O操作是否就緒才能進(jìn)行下一步的操作。此模型中由于不需要為每一個(gè)鏈接請(qǐng)求創(chuàng)建一個(gè)線程,大大減少了線程之間的切換帶來(lái)的巨大開銷。提高了I/O的效率,使得在socket網(wǎng)絡(luò)通信更加高效。但由于NIO在鏈接請(qǐng)求中會(huì)不斷詢問(wèn)I/O操作是否完成,其適合運(yùn)用在短鏈接且并發(fā)量大的場(chǎng)合下。
3.3 AIO技術(shù)簡(jiǎn)介
AIO即為異步非阻塞IO,與NIO不同的是,在這種模式下,客戶端發(fā)起一個(gè)鏈接請(qǐng)求后不在詢問(wèn)服務(wù)器端的I/O操作是否完成便立即返回。在使用過(guò)程中只需直接調(diào)用異步的read和write方法來(lái)讀寫數(shù)據(jù),在讀寫過(guò)程完畢后由操作系統(tǒng)主動(dòng)通知應(yīng)用程序讀寫操作是否完成。由AIO的讀寫過(guò)程可以看出,因?yàn)樵谧x寫完成后客戶端不需要再詢問(wèn)服務(wù)器端是完成了I/O操作,所以AIO非常適合于運(yùn)用在那些并發(fā)量大且長(zhǎng)連接的請(qǐng)求。AIO模型如圖3所示。
AIO中有幾個(gè)比較重要的類:
AsynchronousServerSocket:用來(lái)創(chuàng)建服務(wù)器端的ServerSocket并綁定地址監(jiān)聽端口。
AsynchronousSocketChannel:Socket在異步非阻塞通信中的應(yīng)用,用來(lái)表示一個(gè)連接請(qǐng)求,并用來(lái)在通信過(guò)程中傳遞數(shù)據(jù)。
AsynchronousChannelGroup:異步通道的分組管理,目的是問(wèn)了資源共享。創(chuàng)建AsynchronousChannelGroup時(shí)需要為其綁定一個(gè)線程執(zhí)行器對(duì)象,這個(gè)線程池主要完成兩個(gè)任務(wù):處理I/O事件和派發(fā)CompletionHandler。在創(chuàng)建AsynchronousServerSocket時(shí)需要為其綁定一個(gè)AsynchronousChannelGroup。通過(guò)AsynchronousServerSocket創(chuàng)建的AsynchronousChannelGroup將屬于同一組,共享其中資源。
CompletionHandler:用于定義在異步IO操作完成后的回調(diào)接口。
3.3.1 服務(wù)器端
(1)創(chuàng)建AsynchronousChannelGroup;
(2)創(chuàng)建AsynchronousServerSocketChannel并將它綁定在AsynchronousChannelGroup上;
(3)為AsynchronousServerSocketChannel對(duì)象綁定端口號(hào);
(4)調(diào)用accept()接收客戶端請(qǐng)求實(shí)現(xiàn)CompletionHandler接口調(diào)用讀寫方法進(jìn)行讀寫數(shù)據(jù)。
3.3.2 客戶端
(1)創(chuàng)建AsynchronousSocketChannel;
(2)綁定IP地址和端口號(hào)鏈接服務(wù)低端實(shí)現(xiàn)CompletionHandler接口中方法直接進(jìn)行讀寫數(shù)據(jù)。
3.4 各種I/O技術(shù)比較分析
BIO:同步阻塞I/O,使用難度簡(jiǎn)單,可靠性低,適用于鏈接并發(fā)量小的架構(gòu)且對(duì)服務(wù)器資源依賴更高。
NIO:同步非阻塞I/O,使用難度復(fù)雜,可靠性高,適用于并發(fā)量大且鏈接較短的場(chǎng)景。
AIO:異步非阻塞I/O,使用難度一般,可靠性高,適用于并發(fā)量大且鏈接長(zhǎng)的場(chǎng)景。
4 結(jié)語(yǔ)
傳統(tǒng)網(wǎng)絡(luò)在IO處理方面存在著性能不足的問(wèn)題,NIO與AIO包的引入解決了傳統(tǒng)IO性能瓶頸問(wèn)題,使的Java在網(wǎng)絡(luò)通信中有了更搞得效率。對(duì)于不同的IO來(lái)說(shuō),它們各自有有不同的應(yīng)用領(lǐng)域。對(duì)于那些并發(fā)量小,數(shù)據(jù)傳輸量小的場(chǎng)景來(lái)說(shuō),傳統(tǒng)的BIO完全可以勝任其工作。相反對(duì)于那些對(duì)性能要求比較高,并發(fā)量大且對(duì)IO的要求比較搞得場(chǎng)合來(lái)說(shuō)應(yīng)該選擇NIO或者BIO技術(shù)。如果客戶端與服務(wù)器在長(zhǎng)連接的情況下選擇AIO相比NIO會(huì)更加高效一些。相反,如果是短連接的應(yīng)用領(lǐng)域,則推薦使用NIO。
參考文獻(xiàn)
[1]范寶德,馬建生.Java非阻塞通訊研究[J].微計(jì)算機(jī)信息,2006,22(12-3):116-119.
[2]劉邦桂,李正凡.用Java實(shí)現(xiàn)流式Socket通訊[J].華東交通大學(xué)學(xué)報(bào),2007,24(05):110-112.
[3]封瑋,周世平.基于Java NIO的非阻塞通信的研究與實(shí)現(xiàn)[J].計(jì)算機(jī)系統(tǒng)應(yīng)用,2004(09):32-35.
[5]任小強(qiáng),陳金鷹,李文彬,胡波.網(wǎng)絡(luò)通信之Java Socket多線程通信[J].信息通信,2015(06):206-207.
作者簡(jiǎn)介
王少輝(1992-),男,山西省平順縣人。碩士學(xué)位。現(xiàn)為山東大學(xué)(威海)機(jī)電與信息工程學(xué)院學(xué)生。主要研究方向?yàn)殡娐放c系統(tǒng)。
陳曉鵬(1992-),男,天津市人。碩士學(xué)位?,F(xiàn)為山東大學(xué)(威海)機(jī)電與信息工程學(xué)院學(xué)生。主要研究方向?yàn)殡娐放c系統(tǒng)。
作者單位
山東大學(xué)(威海)機(jī)電與信息工程學(xué)院 山東省威海市 264209