阻塞,還是非阻塞?這就是問(wèn)題所在。無(wú)論在程序員的頭腦中多么高貴……當(dāng)然這不是莎士比亞,本文提出了任何程序員在編寫(xiě) Internet 客戶(hù)程序時(shí)都應(yīng)該考慮的一個(gè)重要問(wèn)題。通信操作應(yīng)該是阻塞的還是非阻塞的?
許多程序員在使用 Java 語(yǔ)言編寫(xiě) Internet 客戶(hù)程序時(shí)并沒(méi)有考慮這個(gè)問(wèn)題,主要是因?yàn)樵谝郧爸挥幸环N選擇――阻塞通信。但是現(xiàn)在 Java 程序員有了新的選擇,因此我們編寫(xiě)的每個(gè)客戶(hù)程序也許都應(yīng)該考慮一下。
非阻塞通信在 Java 2 SDK 的 1.4 版被引入 Java 語(yǔ)言。如果您曾經(jīng)使用該版本編過(guò)程序,可能會(huì)對(duì)新的 I/O 庫(kù)(NIO)留下了印象。在引入它之前,非阻塞通信只有在實(shí)現(xiàn)第三方庫(kù)的時(shí)候才能使用,而第三方庫(kù)常常會(huì)給應(yīng)用程序引入缺陷。
NIO 庫(kù)包含了文件、管道以及客戶(hù)機(jī)和服務(wù)器套接字的非阻塞功能。庫(kù)中缺少的一個(gè)特性是安全的非阻塞套接字連接。在 NIO 或者 JSSE 庫(kù)中沒(méi)有建立安全的非阻塞通道類(lèi),但這并不意味著不能使用安全的非阻塞通信。只不過(guò)稍微麻煩一點(diǎn)。
要完全領(lǐng)會(huì)本文,您需要熟悉:
- Java 套接字通信的概念。您也應(yīng)該實(shí)際編寫(xiě)過(guò)應(yīng)用程序。而且不只是打開(kāi)連接、讀取一行然后退出的簡(jiǎn)單應(yīng)用程序,應(yīng)該是實(shí)現(xiàn) POP3 或 HTTP 之類(lèi)協(xié)議的客戶(hù)機(jī)或通信庫(kù)這樣的程序。
- SSL 基本概念和加密之類(lèi)的概念。基本上就是知道如何設(shè)置一個(gè)安全連接(但不必?fù)?dān)心 JSSE ――這就是關(guān)于它的一個(gè)“緊急教程”)。
- NIO 庫(kù)。
- 在您選擇的平臺(tái)上安裝 Java 2 SDK 1.4 或以后的版本。(我是在 Windows 98 上使用 1.4.1_01 版。)
如果需要關(guān)于這些技術(shù)的介紹,請(qǐng)參閱 參考資料部分。
那么到底什么是阻塞和非阻塞通信呢?
阻塞通信意味著通信方法在嘗試訪(fǎng)問(wèn)套接字或者讀寫(xiě)數(shù)據(jù)時(shí)阻塞了對(duì)套接字的訪(fǎng)問(wèn)。在 JDK 1.4 之前,繞過(guò)阻塞限制的方法是無(wú)限制地使用線(xiàn)程,但這樣常常會(huì)造成大量的線(xiàn)程開(kāi)銷(xiāo),對(duì)系統(tǒng)的性能和可伸縮性產(chǎn)生影響。java.nio 包改變了這種狀況,允許服務(wù)器有效地使用 I/O 流,在合理的時(shí)間內(nèi)處理所服務(wù)的客戶(hù)請(qǐng)求。
沒(méi) 有非阻塞通信,這個(gè)過(guò)程就像我所喜歡說(shuō)的“為所欲為”那樣。基本上,這個(gè)過(guò)程就是發(fā)送和讀取任何能夠發(fā)送/讀取的東西。如果沒(méi)有可以讀取的東西,它就中止 讀操作,做其他的事情直到能夠讀取為止。當(dāng)發(fā)送數(shù)據(jù)時(shí),該過(guò)程將試圖發(fā)送所有的數(shù)據(jù),但返回實(shí)際發(fā)送出的內(nèi)容。可能是全部數(shù)據(jù)、部分?jǐn)?shù)據(jù)或者根本沒(méi)有發(fā)送 數(shù)據(jù)。
阻塞與非阻塞相比確實(shí)有一些優(yōu)點(diǎn),特別是遇到錯(cuò)誤控制問(wèn)題的時(shí)候。在阻塞套接字通信中,如果出現(xiàn)錯(cuò)誤,該訪(fǎng)問(wèn)會(huì)自動(dòng)返回標(biāo)志錯(cuò)誤的代碼。錯(cuò)誤可能是由于網(wǎng)絡(luò)超時(shí)、套接字關(guān)閉或者任何類(lèi)型的 I/O 錯(cuò)誤造成的。在非阻塞套接字通信中,該方法能夠處理的唯一錯(cuò)誤是網(wǎng)絡(luò)超時(shí)。為了檢測(cè)使用非阻塞通信的網(wǎng)絡(luò)超時(shí),需要編寫(xiě)稍微多一點(diǎn)的代碼,以確定自從上一次收到數(shù)據(jù)以來(lái)已經(jīng)多長(zhǎng)時(shí)間了。
哪種方式更好取決于應(yīng)用程序。如果使用的是同步通信,如果數(shù)據(jù)不必在讀取任何數(shù)據(jù)之前處理的話(huà),阻塞通信更好一些,而非阻塞通信則提供了處理任何已經(jīng)讀取的數(shù)據(jù)的機(jī)會(huì)。而異步通信,如 IRC 和聊天客戶(hù)機(jī)則要求非阻塞通信以避免凍結(jié)套接字。
![]() ![]() |
![]()
|
創(chuàng)建傳統(tǒng)的非阻塞客戶(hù)機(jī)套接字
Java NIO 庫(kù)使用通道而非流。通道可同時(shí)用于阻塞和非阻塞通信,但創(chuàng)建時(shí)默認(rèn)為非阻塞版本。但是所有的非阻塞通信都要通過(guò)一個(gè)名字中包含
Channel
的類(lèi)完成。在套接字通信中使用的類(lèi)是
SocketChannel,
而創(chuàng)建該類(lèi)的對(duì)象的過(guò)程不同于典型的套接字所用的過(guò)程,如清單
1 所示。
清單 1. 創(chuàng)建并連接 SocketChannel 對(duì)象
|
必須聲明一個(gè)
SocketChannel
類(lèi)型的指針,但是不能使用
new
操作符創(chuàng)建對(duì)象。相反,必須調(diào)用
SocketChannel
類(lèi)的一個(gè)靜態(tài)方法打開(kāi)通道。打開(kāi)通道后,可以通過(guò)調(diào)用
connect()
方法與它連接。但是當(dāng)該方法返回時(shí),套接字不一定是連接的。為了確保套接字已經(jīng)連接,必須接著調(diào)用
finishConnect()
。
當(dāng)套接字連接之后,非阻塞通信就可以開(kāi)始使用
SocketChannel
類(lèi)的
read()
和
write()
方法了。也可以把該對(duì)象強(qiáng)制轉(zhuǎn)換成單獨(dú)的
ReadableByteChannel
和
WritableByteChannel
對(duì)象。無(wú)論哪種方式,都要對(duì)數(shù)據(jù)使用
Buffer
對(duì)象。因?yàn)?NIO
庫(kù)的使用超出了本文的范圍,我們不再對(duì)此進(jìn)一步討論。
當(dāng)不再需要套接字時(shí),可以使用
close()
方法將其關(guān)閉:
|
這樣就會(huì)同時(shí)關(guān)閉套接字連接和底層的通信通道。
![]() ![]() |
![]()
|
創(chuàng)建替代的非阻塞的客戶(hù)機(jī)套接字
上述方法比傳統(tǒng)的創(chuàng)建套接字連接的例程稍微麻煩一點(diǎn)。不過(guò),傳統(tǒng)的例程也能用于創(chuàng)建非阻塞套接字,不過(guò)需要增加幾個(gè)步驟以支持非阻塞通信。
SocketChannel
對(duì)象中的底層通信包括兩個(gè)
Channel
類(lèi):
ReadableByteChannel
和
WritableByteChannel。
這兩個(gè)類(lèi)可以分別從現(xiàn)有的
InputStream
和
OutputStream
阻塞流中使用
Channels
類(lèi)的
newChannel()
方法創(chuàng)建,如清單 2 所示:
清單 2. 從流中派生通道
|
Channels
類(lèi)也用于把通道轉(zhuǎn)換成流或者 reader 和 writer。這似乎是把通信切換到阻塞模式,但并非如此。如果試圖讀取從通道派生的流,讀方法將拋出
IllegalBlockingModeException
異常。
相反方向的轉(zhuǎn)換也是如此。不能使用
Channels
類(lèi)把流轉(zhuǎn)換成通道而指望進(jìn)行非阻塞通信。如果試圖讀從流派生的通道,讀仍然是阻塞的。但是像編程中的許多事情一樣,這一規(guī)則也有例外。
這種例外適合于實(shí)現(xiàn)
SelectableChannel
抽象類(lèi)的類(lèi)。
SelectableChannel
和它的派生類(lèi)能夠選擇使用阻塞或者非阻塞模式。
SocketChannel
就是這樣的一個(gè)派生類(lèi)。
但是,為了能夠在兩者之間來(lái)回切換,接口必須作為
SelectableChannel
實(shí)現(xiàn)。對(duì)于套接字而言,為了實(shí)現(xiàn)這種能力必須使用
SocketChannel
而不是
Socket
。
回顧一下,要?jiǎng)?chuàng)建套接字,首先必須像通常使用
Socket
類(lèi)那樣創(chuàng)建一個(gè)套接字。套接字連接之后,使用
清單
2中的兩行代碼把流轉(zhuǎn)換成通道。
清單 3. 創(chuàng)建套接字的另一種方法
|
如前所述,這樣并不能實(shí)現(xiàn)非阻塞套接字通信――所有的通信仍然在阻塞模式下。在這種情況下,非阻塞通信必須模擬實(shí)現(xiàn)。模擬層不需要多少代碼。讓我們來(lái)看一看。
模擬層在嘗試讀操作之前首先檢查數(shù)據(jù)的可用性。如果數(shù)據(jù)可讀則開(kāi)始讀。如果沒(méi)有數(shù)據(jù)可用,可能是因?yàn)樘捉幼直魂P(guān)閉,則返回表示這種情況的代碼。在清單
4 中要注意仍然使用了
ReadableByteChannel
讀,盡管
InputStream
完全可以執(zhí)行這個(gè)動(dòng)作。為什么這樣做呢?為了造成是 NIO 而不是模擬層執(zhí)行通信的假象。此外,還可以使模擬層與其他通道更容易結(jié)合,比如向文件通道內(nèi)寫(xiě)入數(shù)據(jù)。
清單 4. 模擬非阻塞的讀操作
|
對(duì)于非阻塞通信,寫(xiě)操作只寫(xiě)入能夠?qū)懙臄?shù)據(jù)。發(fā)送緩沖區(qū)的大小和一次可以寫(xiě)入的數(shù)據(jù)多少有很大關(guān)系。緩沖區(qū)的大小可以通過(guò)調(diào)用
Socket
對(duì)象的
getSendBufferSize()
方法確定。在嘗試非阻塞寫(xiě)操作時(shí)必須考慮到這個(gè)大小。如果嘗試寫(xiě)入比緩沖塊更大的數(shù)據(jù),必須拆開(kāi)放到多個(gè)非阻塞寫(xiě)操作中。太大的單個(gè)寫(xiě)操作可能被阻塞。
清單 5. 模擬非阻塞的寫(xiě)操作
|
與讀操作類(lèi)似,首先要檢查套接字是否仍然連接。但是如果把數(shù)據(jù)寫(xiě)入
WritableByteBuffer
對(duì)象,就像清單 5
那樣,該對(duì)象將自動(dòng)進(jìn)行檢查并在沒(méi)有連接時(shí)拋出必要的異常。在這個(gè)動(dòng)作之后開(kāi)始寫(xiě)數(shù)據(jù)之前,流必須立即被清空,以保證發(fā)送緩沖區(qū)中有發(fā)送數(shù)據(jù)的空間。任何
寫(xiě)操作都要這樣做。發(fā)送到塊中的數(shù)據(jù)與發(fā)送緩沖區(qū)的大小相同。執(zhí)行清除操作可以保證發(fā)送緩沖不會(huì)溢出而導(dǎo)致寫(xiě)操作被阻塞。
因?yàn)榧俣▽?xiě)操作只能寫(xiě)入能夠?qū)懙膬?nèi)容,這個(gè)過(guò)程還必須檢查套接字保證它在每個(gè)數(shù)據(jù)塊寫(xiě)入后仍然是打開(kāi)的。如果在寫(xiě)入數(shù)據(jù)時(shí)套接字被關(guān)閉,則必須中止寫(xiě)操作并返回套接字關(guān)閉之前能夠發(fā)送的數(shù)據(jù)量。
BufferedOutputReader
可用于模擬非阻塞寫(xiě)操作。如果試圖寫(xiě)入超過(guò)緩沖區(qū)兩倍長(zhǎng)度的數(shù)據(jù),則直接寫(xiě)入緩沖區(qū)整倍數(shù)長(zhǎng)度的數(shù)據(jù)(緩沖余下的數(shù)據(jù))。比如說(shuō),如果緩沖區(qū)的長(zhǎng)度是
256 字節(jié)而需要寫(xiě)入 529 字節(jié)的數(shù)據(jù),則該對(duì)象將清除當(dāng)前緩沖區(qū)、發(fā)送 512 字節(jié)然后保存剩下的 17 字節(jié)。
對(duì)于非阻塞寫(xiě)而言,這并非我們所期望的。我們希望分次把數(shù)據(jù)寫(xiě)入同樣大小的緩沖區(qū)中,并最終把全部數(shù)據(jù)都寫(xiě)完。如果發(fā)送的大塊數(shù)據(jù)留下一些數(shù)據(jù)被緩沖,那么在所有數(shù)據(jù)被發(fā)送的時(shí)候,寫(xiě)操作就會(huì)被阻塞。
整個(gè)模擬層可以放到一個(gè)類(lèi)中,以便更容易和應(yīng)用程序集成。如果要這樣做,我建議從
ByteChannel
派生這個(gè)類(lèi)。這個(gè)類(lèi)可以強(qiáng)制轉(zhuǎn)換成單獨(dú)的
ReadableByteChannel
和
WritableByteChannel
類(lèi)。
清單 6 給出了從
ByteChannel
派生的模擬層類(lèi)模板的一個(gè)例子。本文后面將一直使用這個(gè)類(lèi)表示通過(guò)阻塞連接執(zhí)行的非阻塞操作。
清單 6. 模擬層的類(lèi)模板
|
使用新建的模擬層創(chuàng)建套接字非常簡(jiǎn)單。只要像通常那樣創(chuàng)建
Socket
對(duì)象,然后創(chuàng)建
nbChannel
對(duì)象就可以了,如清單 7 所示:
清單 7. 使用模擬層
|
![]() ![]() |
![]()
|
創(chuàng)建傳統(tǒng)的非阻塞服務(wù)器套接字
服務(wù)器端的非阻塞套接字和客戶(hù)端上的沒(méi)有很大差別。稍微麻煩一點(diǎn)的只是建立接受輸入連接的套接字。套接字必須通過(guò)從服務(wù)器套接字通道派生一個(gè)阻塞的服務(wù)器套接字綁定到阻塞模式。清單 8 列出了需要做的步驟。
清單 8. 創(chuàng)建非阻塞的服務(wù)器套接字(SocketChannel)
|
與客戶(hù)機(jī)套接字通道相似,服務(wù)器套接字通道也必須打開(kāi)而不是使用
new
操作符或者構(gòu)造函數(shù)。在打開(kāi)之后,必須派生服務(wù)器套接字對(duì)象以便把套接字通道綁定到一個(gè)端口。一旦套接字被綁定,服務(wù)器套接字對(duì)象就可以丟棄了。
通道使用
accept()
方法接收到來(lái)的連接并把它們轉(zhuǎn)給套接字通道。一旦接收了到來(lái)的連接并轉(zhuǎn)給套接字通道對(duì)象,通信就可以通過(guò)
read()
和
write()
方法開(kāi)始進(jìn)行了。
![]() ![]() |
![]()
|
實(shí)際上,并非真正的替代。因?yàn)榉?wù)器套接字通道必須使用服務(wù)器套接字對(duì)象綁定,為何不完全繞開(kāi)服務(wù)器套接字通道而僅使用服務(wù)器套接字對(duì)象呢?不過(guò)這里的通信不使用
SocketChannel
,而要使用模擬層
nbChannel。
清單 9. 建立服務(wù)器套接字的另一種方法
|
![]() ![]() |
![]()
|
創(chuàng)建SSL連接,我們要分別從客戶(hù)端和服務(wù)器端考察。
創(chuàng)建 SS L連接的傳統(tǒng)方法涉及到使用套接字工廠(chǎng)和其他一些東西。我將不會(huì)詳細(xì)討論如何創(chuàng)建SSL連接,不過(guò)有一本很好的教程,“Secure your sockets with JSSE”(請(qǐng)參閱 參考資料),從中您可以了解到更多的信息。
創(chuàng)建 SSL 套接字的默認(rèn)方法非常簡(jiǎn)單,只包括幾個(gè)很短的步驟:
- 創(chuàng)建套接字工廠(chǎng)。
- 創(chuàng)建連接的套接字。
- 開(kāi)始握手。
- 派生流。
- 通信。
清單 10 說(shuō)明了這些步驟:
清單 10. 創(chuàng)建安全的客戶(hù)機(jī)套接字
|
默認(rèn)方法不包括客戶(hù)驗(yàn)證、用戶(hù)證書(shū)和其他特定連接可能需要的東西。
建立SSL服務(wù)器連接的傳統(tǒng)方法稍微麻煩一點(diǎn),需要加上一些類(lèi)型轉(zhuǎn)換。因?yàn)檫@些超出了本文的范圍,我將不再進(jìn)一步介紹,而是說(shuō)說(shuō)支持SSL服務(wù)器連接的默認(rèn)方法。
創(chuàng)建默認(rèn)的 SSL 服務(wù)器套接字也包括幾個(gè)很短的步驟:
- 創(chuàng)建服務(wù)器套接字工廠(chǎng)。
- 創(chuàng)建并綁定服務(wù)器套接字。
- 接受傳入的連接。
- 開(kāi)始握手。
- 派生流。
- 通信。
盡管看起來(lái)似乎與客戶(hù)端的步驟相似,要注意這里去掉了很多安全選項(xiàng),比如客戶(hù)驗(yàn)證。
清單 11 說(shuō)明這些步驟:
清單 11. 創(chuàng)建安全的服務(wù)器套接字
|
![]() ![]() |
![]()
|
要精心實(shí)現(xiàn)安全的非阻塞連接,也需要分別從客戶(hù)端和服務(wù)器端來(lái)看。
在客戶(hù)端建立安全的非阻塞連接非常簡(jiǎn)單:
- 創(chuàng)建并連接
Socket
對(duì)象。 - 把
Socket
對(duì)象添加到模擬層上。 - 通過(guò)模擬層通信。
清單 12 說(shuō)明了這些步驟:
清單 12. 創(chuàng)建安全的客戶(hù)機(jī)連接
|
利用前面給出的
模擬層類(lèi)
就可以實(shí)現(xiàn)非阻塞的安全連接。因?yàn)榘踩捉幼滞ǖ啦荒苁褂?
SocketChannel
類(lèi)打開(kāi),而 Java API
中又沒(méi)有完成這項(xiàng)工作的類(lèi),所以創(chuàng)建了一個(gè)模擬類(lèi)。模擬類(lèi)可以實(shí)現(xiàn)非阻塞通信,無(wú)論使用安全套接字連接還是非安全套接字連接。
列出的步驟包括默認(rèn)的安全設(shè)置。對(duì)于更高級(jí)的安全性,比如用戶(hù)證書(shū)和客戶(hù)驗(yàn)證, 參考資料 部分提供了說(shuō)明如何實(shí)現(xiàn)的文章。
在服務(wù)器端建立套接字需要對(duì)默認(rèn)安全稍加設(shè)置。但是一旦套接字被接收和路由,設(shè)置必須與客戶(hù)端的設(shè)置完全相同,如清單 13 所示:
清單 13. 創(chuàng)建安全的非阻塞服務(wù)器套接字
|
同樣,要記住這些步驟使用的是默認(rèn)安全設(shè)置。
![]() ![]() |
![]()
|
多數(shù) Internet 客戶(hù)機(jī)應(yīng)用程序,無(wú)論使用 Java 語(yǔ)言還是其他語(yǔ)言編寫(xiě),都需要提供安全和非安全連接。Java Secure Socket Extensions 庫(kù)使得這項(xiàng)工作非常容易,我最近在編寫(xiě)一個(gè) HTTP 客戶(hù)庫(kù)時(shí)就使用了這種方法。
SSLSocket
類(lèi)派生自
Socket。
您可能已經(jīng)猜到我要怎么做了。所需要的只是該對(duì)象的一個(gè)
Socket
指針。如果套接字連接不使用SSL,則可以像通常那樣創(chuàng)建套接字。如果要使用 SSL,就稍微麻煩一點(diǎn),但此后的代碼就很簡(jiǎn)單了。清單
14 給出了一個(gè)例子:
清單 14. 集成安全的和非安全的客戶(hù)機(jī)連接
|
創(chuàng)建通道之后,如果套接字使用了SSL,那么就是安全通信,否則就是普通通信。如果使用了 SSL,關(guān)閉套接字將導(dǎo)致握手中止。
這種設(shè)置的一種可能是使用兩個(gè)單獨(dú)的類(lèi)。一個(gè)類(lèi)負(fù)責(zé)處理通過(guò)套接字沿著與非安全套接字的連接進(jìn)行的所有通信。一個(gè)單獨(dú)的類(lèi)應(yīng)該負(fù)責(zé)創(chuàng)建安全的連接,包括安全連接的所有必要設(shè)置,無(wú)論是否是默認(rèn)的。安全類(lèi)應(yīng)該直接插入通信類(lèi),只有在使用安全連接時(shí)被調(diào)用。
![]() ![]() |
![]()
|
本文提出的方法是我所知道的把 JSSE 和 NIO 集成到同一代碼中以提供非阻塞安全通信的最簡(jiǎn)單方法。盡管還有其他方法,但是都需要準(zhǔn)備實(shí)現(xiàn)這一過(guò)程的程序員花費(fèi)大量的時(shí)間和精力。
一種可能是使用 Java Cryptography Extensions 在 NIO 上實(shí)現(xiàn)自己的 SSL 層。另一種方法是修改現(xiàn)有的稱(chēng)為 EspreSSL (以前稱(chēng)為 jSSL)的定制 SSL 層, 把它改到 NIO 庫(kù)中。我建議只有在您有很充裕的時(shí)間時(shí)才使用這兩種方法。
參考資料 部分的可下載 zip 文件提供了示例代碼,幫助您實(shí)踐本文所述的技術(shù),其中包括:
- nbChannel,清單 7 所介紹的模擬層的源代碼。
- 連接到 Verisign's Web 站點(diǎn)并下載主頁(yè)的示例 HTTPS 客戶(hù)程序。
- 一個(gè)簡(jiǎn)單的非阻塞安全服務(wù)器 (Secure Daytime Server)。
- 集成的安全和非安全客戶(hù)程序。
![]() ![]() |
![]()
|
- 您可以參閱本文在 developerWorks 全球站點(diǎn)上的
英文原文.
- 下載本文的
源代碼。
- "
Introduction
to Cryptography" 通過(guò)介紹 SSL 提供了加密的基本原理(PDF 格式)。
- "
Secure
Your Sockets with JSSE" 是應(yīng)用 JSSE 的入門(mén)指南。
- "
Merlin 給 Java 平臺(tái)帶來(lái)了非阻塞 I/O" (
developerWorks,2002
年 3 月)介紹了 Merlin 的 NIO 包的非阻塞特性,并提供了套接字編程的例子。
- "
Merlin 的新 I/O 緩沖區(qū)的輸入和輸出" (
developerWorks,2003
年 3 月) 展示了如何為讀/寫(xiě)基本數(shù)據(jù)類(lèi)型這樣的任務(wù)操作數(shù)據(jù)緩沖區(qū)和使用內(nèi)存映射文件。
- "
為高級(jí) JSSE 開(kāi)發(fā)人員定制 SSL" (
developerWorks,2002
年 9 月) 示范了如何編程繞過(guò) SSL 的一些限制。
- 教程 "
Getting
started with new I/O (NIO)" (
developerWorks,2003
年 7 月)非常詳細(xì)地討論了 NIO 庫(kù),從高級(jí)概念到隱藏的編程細(xì)節(jié)。
-
IBMJSSE
Overview概要介紹了 Java Secure Socket Extension。
-
JSSE
reference guide是該技術(shù)巨細(xì)無(wú)遺的參考資料。
- Ron Hitchens 所著的
Java
NIO(O'Reilly & Associates, 2002),深入探索了 1.4 版的新I/O功能。
-
Java
NIO還有一個(gè)支持網(wǎng)站,
JavaNIO.info,
提供了代碼開(kāi)發(fā)的幻燈片、GUI 演示工具和該書(shū)的其他補(bǔ)充資料。
- 在
developerWorks
Java 技術(shù)專(zhuān)區(qū)
上可以找到數(shù)百篇關(guān)于 Java 各個(gè)方面的文章。
![]() ![]() |
![]()
|
![]() |
||
|
![]() |
Kenneth Ballard 目前在內(nèi)布拉斯加州珀魯州立大學(xué)學(xué)習(xí)計(jì)算機(jī)科學(xué)。他還是校內(nèi)的學(xué)生報(bào)紙 Peru State Times 的職業(yè)作者。他從愛(ài)荷華州 Creston 的 Southwestern Community College 獲得了計(jì)算機(jī)編程 Associate of Science 學(xué)位,在那里作為 PC 技術(shù)人員參加了一個(gè)工作效率研究項(xiàng)目。他的研究范圍包括 Java 技術(shù)、C++、COBOL、Visual Basic 和網(wǎng)絡(luò)。可以通過(guò) kenneth.ballard@ptk.org 與 Kenneth 聯(lián)系。 |