對(duì)相關(guān)類的簡(jiǎn)單介紹 java.nio.*, 據(jù)說(shuō)它提供了一些更加底層的一些功能,如:類似windows環(huán)境下的AsyncSocket類的異步操作的功能,能顯著降低server端程序的線程管理開銷。 因?yàn)榇蠖鄶?shù)應(yīng)用是建立在TCP之上,所以在此只說(shuō)說(shuō)SocketChannel,ServerSocketChannel,Selector和ByteBuffer這幾個(gè)類.前三個(gè)最終都源自channel類。而channel 類,可以理解為在具體I/O或文件對(duì)象之上抽象的一個(gè)操作對(duì)象,我們通過(guò)操作channel的讀寫達(dá)到對(duì)其對(duì)應(yīng)的文件或I/O對(duì)象(包括socket)讀寫的目的。讀寫的內(nèi)容在內(nèi)存中放在ByteBuffer類提供的緩沖區(qū)。總而言之,channel作為一個(gè)橋梁,連接了I/O對(duì)象和內(nèi)存中的ByteBuffer,實(shí)現(xiàn)了I/O的更高效的存取。 一個(gè)基于TCP的服務(wù)器端程序,必然有個(gè)偵聽端和若干個(gè)通信端,它們?cè)趎io中由對(duì)應(yīng)的ServerSocketChannel 和SocketChannel類來(lái)實(shí)現(xiàn)。為了達(dá)到異步I/O操作的目的,需要Selector類,它能檢測(cè)到I/O對(duì)象的狀態(tài)。
SocketChannel類是抽象類,通過(guò)調(diào)用它的靜態(tài)函數(shù)open(),可生成一個(gè)SocketChannel對(duì)象,該對(duì)象對(duì)應(yīng)一個(gè)java.net.Socket,可通過(guò)SocketChannel.socket()獲得,而其對(duì)應(yīng)的Socket也可通過(guò)調(diào)用函數(shù)getChannel()得到已建立的相應(yīng)SocketChannel。 SocketChannel與它的socket是一一對(duì)應(yīng)的。SocketChannel的操作與Socket也很相似.
ServerSocketChannel也是通過(guò)調(diào)用它的靜態(tài)函數(shù)open()生成的,只是它不能直接調(diào)用bind()函數(shù)來(lái)綁定一個(gè)地址,需要它對(duì)應(yīng)的ServerSocket來(lái)完成綁定工作,一般可按如下步驟做:
羅嗦了半天,還是看看最簡(jiǎn)單的C/S實(shí)現(xiàn)吧,服務(wù)器提供了基本的回射(echo)功能,其中提供了較詳細(xì)的注釋。
源碼分析
1.服務(wù)器端:
在當(dāng)前目錄下運(yùn)行: javac AsynServer.java 后,若無(wú)編譯出錯(cuò),接下來(lái)可運(yùn)行: java AsynServer 或 java AsynServer ×××(端口號(hào)) 上述服務(wù)程序在運(yùn)行時(shí),可指定其偵聽端口,否則程序會(huì)取8848為默認(rèn)端口。
2.客戶端的簡(jiǎn)單示例:
在當(dāng)前目錄下運(yùn)行: javac AsynClient.java 后,若無(wú)編譯出錯(cuò),確認(rèn)AsyncServer已經(jīng)運(yùn)行的情況下,接下來(lái)可運(yùn)行: java AsynClient hostname 或 java AsynClient hostname ×××(端口號(hào)) 并按提示進(jìn)行操作即可。
總結(jié) 總的來(lái)說(shuō),用nio進(jìn)行網(wǎng)絡(luò)編程還是很有新意的,服務(wù)器端軟件能在一個(gè)線程中維護(hù)與眾多客戶端的通信連接。筆者在本文中試圖用一個(gè)典型的回射例子說(shuō)明如何用nio建立最基本的C/S應(yīng)用。希望大家能試著用用它。 另外,筆者在實(shí)踐中也發(fā)現(xiàn)nio在應(yīng)用中存在的一些難題,比如如何應(yīng)用SocketChannel的繼承類,以及如何在socketchannel之上應(yīng)用SSL(Secure Socket Layer)等等,因而希望這篇文章只是拋磚引玉,引起大家對(duì)nio作進(jìn)一步的討論。