本書主要介紹Java語言中高性能處理的原理技術(shù):NIO和Socket。非常詳細(xì)地講解了NIO中的緩沖區(qū)、通道、選擇器、編碼,以及使用Socket技術(shù)實現(xiàn)TCP/IP和UDP編程,細(xì)化到了演示全部SocketOption的特性,這對理解基于NIO和Socket技術(shù)為基礎(chǔ)所開發(fā)的NIO框架是非常有好處的,本書以案例為入口,將大部分在開發(fā)中常見的NIO和Socket的技術(shù)點都做了演示,細(xì)化到API級。在互聯(lián)網(wǎng)技術(shù)日新月異的時代,Netty以及Kafka等這些高性能處理框架都在底層應(yīng)用到了NIO和Socket,所以當(dāng)你目前是有計劃進軍互聯(lián)網(wǎng)技術(shù)時,本書也許會帶給你一個方向。
1)技術(shù)暢銷書作者撰寫,掌握高并發(fā)與網(wǎng)絡(luò)編程基石技術(shù):NIO與Soket
2)細(xì)化到特性級別,涵蓋領(lǐng)域中核心技術(shù),包括緩沖區(qū)、通道、選擇器以及基于Socket 的TCP/IP和UDP編程
Preface?前 言為什么要寫這本書早在幾年前,筆者就曾想過整理一份基于Java語言的NIO與Socket相關(guān)的稿件,因為市面上大部分的Java書籍都是以1章或2章的篇幅介紹NIO與Socket技術(shù),并沒有完整地覆蓋該技術(shù)的知識點,而限于當(dāng)時的時間及精力,一直沒有如愿。
機會終于來了,公司要搭建基礎(chǔ)構(gòu)架知識體系,我負(fù)責(zé)公司該技術(shù)方向的培訓(xùn),這重燃了我對NIO和Socket技術(shù)的熱情。在學(xué)習(xí)Java技術(shù)的過程中,當(dāng)學(xué)習(xí)了Java SE/Java EE之后想探索更深層次的技術(shù),如大數(shù)據(jù)、分布式和高并發(fā)類等,可能會遇到針對NIO、Socket的學(xué)習(xí),但NIO和Socket技術(shù)的學(xué)習(xí)并不像JDBC一樣簡單,學(xué)習(xí)NIO和Socket時可能要遇到很多的問題。為了在該技術(shù)領(lǐng)域有更高的追求,我將NIO和Socket的技術(shù)點以教案的方式進行了整理,并在公司中與同事一起進行學(xué)習(xí)和交流,同事的反響非常熱烈。若干年前的心愿終于達(dá)成,同事們也很期待這本書能早日出版發(fā)行,那樣他們就有真正的紙質(zhì)參考資料了。希望本書能夠受到其他學(xué)習(xí)NIO和Socket的讀者喜愛,這是我最大的心愿。
本書介紹NIO和Socket開發(fā)中最值得關(guān)注的內(nèi)容,并給出個人的一些想法和見解,希望拓寬讀者的學(xué)習(xí)思路。
在學(xué)習(xí)NIO和Socket技術(shù)之前,建議先了解一下多線程與并發(fā)相關(guān)的知識,這對設(shè)計和理解代碼有非常大的幫助。多線程方面的資料推薦《Java多線程編程核心技術(shù)》,并發(fā)相關(guān)的資料推薦《Java并發(fā)編程:核心方法與框架》,這兩本書都是筆者編著的,希望可以給讀者帶來一些幫助。
本書特色在本書寫作的過程中,我盡量做到言簡意賅,并且全部用演示案例的方式來講解技術(shù)知識點,使讀者看到代碼及運行結(jié)果后就可以知道此項目要解決的是什么問題。這類似于網(wǎng)絡(luò)中的博客風(fēng)格,讓讀者用最短的時間學(xué)習(xí)知識點,明白知識點的應(yīng)用方式及使用時的注意事項,取得快速學(xué)習(xí)并解決相應(yīng)問題的效果。
讀者對象Java程序員系統(tǒng)架構(gòu)師大數(shù)據(jù)開發(fā)者其他對NIO和Socket技術(shù)感興趣的人員如何閱讀本書本著實用、易懂的學(xué)習(xí)原則,本書通過6章內(nèi)容來介紹Java多線程相關(guān)的技術(shù)。
第1章介紹NIO技術(shù)中的緩沖區(qū),包括Buffer、ByteBuffer、CharBuffer類的核心API的使用。
第2章介紹NIO技術(shù)中的Channel(通道)類的繼承關(guān)系、核心接口的作用,并重點介紹FileChannel類的使用,以增加讀者對NIO操作File類的熟悉度。
第3章介紹如何使用NetworkInterface類獲得網(wǎng)絡(luò)接口的信息,包括IP地址、子網(wǎng)掩碼等,還會介紹InetAddress和InterfaceAddress類的常見API。如果進行Java開發(fā),且基于Socket技術(shù),那么這章可以給你需要的信息。
第4章介紹如何使用Java語言實現(xiàn)Socket通信。Socket通信是基于TCP/IP和UDP實現(xiàn)的。另外,將介紹ServerSocket、Socket、DatagramSocket和DatagramPacket類的全部API。只有熟練掌握Socket技術(shù)后,在閱讀相關(guān)網(wǎng)絡(luò)框架的源代碼時才不會迷茫。也就是說,如果讀者想要進行Java高性能后臺處理,那么必須要學(xué)習(xí)Socket,并且它是進行細(xì)化學(xué)習(xí)的基礎(chǔ)。
第5章介紹NIO技術(shù)中最重要的Selector(選擇器)技術(shù)。NIO技術(shù)的核心多路復(fù)用就是在此章體現(xiàn)的。學(xué)習(xí)這章內(nèi)容需要有Socket的編程基礎(chǔ),這就是為什么在前面用兩章篇幅來介紹Java的Socket編程的原因。同步非阻塞可以大幅度提升程序運行的效率,就在此章體會一下吧。
第6章介紹AIO。AIO是異步IO,NIO是非阻塞IO。AIO在NIO的基礎(chǔ)上實現(xiàn)了異步執(zhí)行、回調(diào)處理等高級功能,可以在不同的場景使用AIO或NIO,可以說NIO和AIO是Java高級程序員、架構(gòu)師等必須要掌握的技術(shù)。
勘誤和支持由于筆者的水平有限,加之編寫倉促,書中難免會出現(xiàn)一些錯誤或者不準(zhǔn)確的地方,懇請讀者批評指正,期待能夠得到你們的真摯反饋,在技術(shù)之路上互勉共進。若讀者想與我進行技術(shù)交流,可發(fā)電子郵件到279377921@qq.com。
致謝感謝所在單位領(lǐng)導(dǎo)的支持與厚愛,使我在技術(shù)道路上更有信心。
感謝機械工業(yè)出版社華章公司的高婧雅,始終支持我的寫作,你是我最愛的編輯。因為你們的鼓勵和幫助,所以我才會如此順利地完成了這本書的寫作。
高洪巖
高洪巖,某世界500強項目經(jīng)理,有10年Java相關(guān)開發(fā)經(jīng)驗,精通Java語言,擅長J2EE、EJB、Android、報表和多線程,以及并發(fā)相關(guān)的技術(shù)內(nèi)容,理論與實踐經(jīng)驗頗豐。著有《Java多線程編程核心技術(shù)》《Java并發(fā)編程:核心方法與框架》《NIO與Socket編程技術(shù)指南》《Java EE核心框架實戰(zhàn) 第2版》《Jasper Reports iReport報表開發(fā)詳解》《Android學(xué)習(xí)精要》等書籍。
目 錄?Contents
前 言
第1章緩沖區(qū)的使用 1
1.1NIO概述 5
1.2緩沖區(qū)介紹 6
1.3Buffer類的使用 7
1.3.1包裝數(shù)據(jù)與獲得容量 7
1.3.2限制獲取與設(shè)置 10
1.3.3位置獲取與設(shè)置 12
1.3.4剩余空間大小獲取 13
1.3.5使用Buffer mark()方法處理標(biāo)記 14
1.3.6知識點細(xì)化測試 15
1.3.7判斷只讀 22
1.3.8直接緩沖區(qū) 22
1.3.9還原緩沖區(qū)的狀態(tài) 23
1.3.10對緩沖區(qū)進行反轉(zhuǎn) 24
1.3.11判斷是否有底層實現(xiàn)的數(shù)組 28
1.3.12判斷當(dāng)前位置與限制之間是否有剩余元素 29
1.3.13重繞緩沖區(qū) 30
1.3.14獲得偏移量 32
1.3.15使用List.toArray(T[])轉(zhuǎn)成數(shù)組類型 33
1.4ByteBuffer類的使用 34
1.4.1創(chuàng)建堆緩沖區(qū)與直接緩沖區(qū) 35
1.4.2直接緩沖區(qū)與非直接緩沖區(qū)的運行效率比較 37
1.4.3包裝wrap數(shù)據(jù)的處理 39
1.4.4put(byte b)和get()方法的使用與position自增特性 40
1.4.5put(byte[] src, int offset, int length)和get(byte[] dst, int offset, int length)方法的使用 41
1.4.6put(byte[] src)和get(byte[] dst)方法的使用 46
1.4.7put(int index, byte b)和get(int index)方法的使用與position不變 49
1.4.8put(ByteBuffer src)方法的使用 50
1.4.9putType()和getType()方法的使用 51
1.4.10slice()方法的使用與arrayOffSet()為非0的測試 53
1.4.11轉(zhuǎn)換為CharBuffer字符緩沖區(qū)及中文的處理 54
1.4.12轉(zhuǎn)換為其他類型的緩沖區(qū) 58
1.4.13設(shè)置與獲得字節(jié)順序 63
1.4.14創(chuàng)建只讀緩沖區(qū) 65
1.4.15壓縮緩沖區(qū) 65
1.4.16比較緩沖區(qū)的內(nèi)容 66
1.4.17復(fù)制緩沖區(qū) 70
1.4.18對緩沖區(qū)進行擴容 72
1.5CharBuffer類的API使用 73
1.5.1重載append(char)/append(Char-Sequence)/append(CharSequence, start, end)方法的使用 73
1.5.2讀取相對于當(dāng)前位置的給定索引處的字符 74
1.5.3put(String src)、int read(CharBuffer target)和subSequence(int start, int end)方法的使用 74
1.5.4static CharBuffer wrap(Char-Sequence csq, int start, int end)方法的使用 76
1.5.5獲得字符緩沖區(qū)的長度 76
1.6小結(jié) 77
第2章通道和FileChannel類的使用 78
2.1通道概述 78
2.2通道接口的層次結(jié)構(gòu) 80
2.2.1AsynchronousChannel接口的介紹 82
2.2.2AsynchronousByteChannel接口的介紹 84
2.2.3ReadableByteChannel接口的介紹 84
2.2.4ScatteringByteChannel接口的介紹 85
2.2.5WritableByteChannel接口的介紹 86
2.2.6GatheringByteChannel接口的介紹 87
2.2.7ByteChannel接口的介紹 88
2.2.8SeekableByteChannel接口的介紹 89
2.2.9NetworkChannel接口的介紹 90
2.2.10MulticastChannel接口的介紹 91
2.2.11InterruptibleChannel接口的介紹 92
2.3AbstractInterruptibleChannel類的介紹 93
2.4FileChannel類的使用 95
2.4.1寫操作與位置的使用 97
2.4.2讀操作 100
2.4.3批量寫操作 106
2.4.4批量讀操作 109
2.4.5部分批量寫操作 117
2.4.6部分批量讀操作 120
2.4.7向通道的指定position位置寫入數(shù)據(jù) 128
2.4.8讀取通道指定位置的數(shù)據(jù) 130
2.4.9設(shè)置位置與獲得大小 135
2.4.10截斷緩沖區(qū) 136
2.4.11將數(shù)據(jù)傳輸?shù)狡渌蓪懭胱止?jié)通道 138
2.4.12將字節(jié)從給定可讀取字節(jié)通道傳輸?shù)酱送ǖ赖奈募? 141
2.4.13執(zhí)行鎖定操作 145
2.4.14FileLock lock()方法的使用 160
2.4.15獲取通道文件給定區(qū)域的鎖定 160
2.4.16FileLock tryLock()方法的使用 162
2.4.17FileLock類的使用 162
2.4.18強制將所有對通道文件的更新寫入包含文件的存儲設(shè)備 165
2.4.19將通道文件區(qū)域直接映射到內(nèi)存 167
2.4.20打開一個文件 174
2.4.21判斷當(dāng)前通道是否打開 181
2.5小結(jié) 182
第3章獲取網(wǎng)絡(luò)設(shè)備信息 183
3.1NetworkInterface類的常用方法 184
3.1.1獲得網(wǎng)絡(luò)接口的基本信息 186
3.1.2獲取MTU大小 189
3.1.3子接口的處理 190
3.1.4獲得硬件地址 192
3.1.5獲得IP地址 194
3.1.6InterfaceAddress類的使用 200
3.1.7判斷是否為點對點設(shè)備 202
3.1.8是否支持多播 202
3.2NetworkInterface類的靜態(tài)方法 204
3.2.1根據(jù)索引獲得NetworkInterface對象 204
3.2.2根據(jù)網(wǎng)絡(luò)接口名稱獲得NetworkInterface對象 204
3.2.3根據(jù)IP地址獲得NetworkInterface對象 205
3.3小結(jié) 205
第4章實現(xiàn)Socket通信 206
4.1基于TCP的Socket通信 206
4.1.1驗證ServerSocket類的accept()方法具有阻塞特性 207
4.1.2驗證Socket中InputStream類的read()方法也具有阻塞特性 210
4.1.3客戶端向服務(wù)端傳遞字符串 212
4.1.4服務(wù)端向客戶端傳遞字符串 213
4.1.5允許多次調(diào)用write()方法進行寫入操作 215
4.1.6實現(xiàn)服務(wù)端與客戶端多次的往來通信 216
4.1.7調(diào)用Stream的close()方法造成Socket關(guān)閉 219
4.1.8使用Socket傳遞PNG圖片文件 221
4.1.9TCP連接的3次握手過程 222
4.1.10標(biāo)志位SYN與ACK值的自增特性 225
4.1.11TCP斷開連接的4次揮手過程 226
4.1.12握手的時機與立即傳數(shù)據(jù)的特性 227
4.1.13結(jié)合多線程Thread實現(xiàn)通信 228
4.1.14服務(wù)端與客戶端互傳對象以及I/O流順序問題 231
4.2ServerSocket類的使用 233
4.2.1接受accept與超時Timeout 233
4.2.2構(gòu)造方法的backlog參數(shù)含義 235
4.2.3參數(shù)backlog的默認(rèn)值 237
4.2.4構(gòu)造方法ServerSocket (int port, int backlog, InetAddress bindAddr)的使用 238
4.2.5綁定到指定的Socket地址 240
4.2.6綁定到指定的Socket地址并設(shè)置backlog數(shù)量 242
4.2.7獲取本地SocketAdress對象以及本地端口 243
4.2.8InetSocketAddress類的使用 244
4.2.9關(guān)閉與獲取關(guān)閉狀態(tài) 247
4.2.10判斷Socket綁定狀態(tài) 248
4.2.11獲得IP地址信息 249
4.2.12Socket選項ReuseAddress 249
4.2.13Socket選項ReceiveBuffer-
Size 257
4.3Socket類的使用 259
4.3.1綁定bind與connect以及端口生成的時機 259
4.3.2連接與超時 261
4.3.3獲得遠(yuǎn)程端口與本地端口 262
4.3.4獲得本地InetAddress地址與本地SocketAddress地址 263
4.3.5獲得遠(yuǎn)程InetAddress與遠(yuǎn)程SocketAddress()地址 264
4.3.6套接字狀態(tài)的判斷 265
4.3.7開啟半讀與半寫狀態(tài) 266
4.3.8判斷半讀半寫狀態(tài) 268
4.3.9Socket選項TcpNoDelay 270
4.3.10Socket選項SendBufferSize 274
4.3.11Socket選項Linger 276
4.3.12Socket選項Timeout 287
4.3.13Socket選項OOBInline 288
4.3.14Socket選項KeepAlive 291
4.3.15Socket選項TrafficClass 293
4.4基于UDP的Socket通信 294
4.4.1使用UDP實現(xiàn)Socket通信 295
4.4.2測試發(fā)送超大數(shù)據(jù)量的包導(dǎo)致數(shù)據(jù)截斷的情況 297
4.4.3Datagram Packet類中常用API的使用 299
4.4.4使用UDP實現(xiàn)單播 300
4.4.5使用UDP實現(xiàn)廣播 301
4.4.6使用UDP實現(xiàn)組播 303
4.5小結(jié) 305
第5章選擇器的使用 306
5.1選擇器與I/O多路復(fù)用 306
5.2核心類Selector、SelectionKey和
SelectableChannel的關(guān)系 307
5.3通道類AbstractInterruptibleChannel與接口InterruptibleChannel的介紹 310
5.4通道類SelectableChannel的介紹 311
5.5通道類AbstractSelectableChannel的介紹 313
5.6通道類ServerSocketChannel與接口NetworkChannel的介紹 313
5.7ServerSocketChannel類、Selector和SelectionKey的使用 315
5.7.1獲得ServerSocketChannel與ServerSocket socket對象 316
5.7.2執(zhí)行綁定操作 317
5.7.3執(zhí)行綁定操作與設(shè)置backlog 317
5.7.4阻塞與非阻塞以及accept()方法的使用效果 318
5.7.5獲得Selector對象 320
5.7.6執(zhí)行注冊操作與獲得SelectionKey對象 321
5.7.7判斷注冊的狀態(tài) 322
5.7.8將通道設(shè)置成非阻塞模式再注冊到選擇器 323
5.7.9使用configureBlocking (false)方法解決異常 323
5.7.10判斷打開的狀態(tài) 324
5.7.11獲得阻塞鎖對象 325
5.7.12獲得支持的SocketOption列表 325
5.7.13獲得與設(shè)置SocketOption 327
5.7.14獲得SocketAddress對象 327
5.7.15阻塞模式的判斷 328
5.7.16根據(jù)Selector找到對應(yīng)的SelectionKey 328
5.7.17獲得SelectorProvider對象 329
5.7.18通道注冊與選擇器 330
5.7.19返回此通道所支持的操作 332
5.7.20執(zhí)行Connect連接操作 333
5.7.21判斷此通道上是否正在進行連接操作 336
5.7.22完成套接字通道的連接過程 338
5.7.23類FileChannel中的long tran-sferTo (position, count, Writable-ByteChannel)方法的使用 340
5.7.24方法public static SocketChannel open (SocketAddress remote)與SocketOption的執(zhí)行順序 342
5.7.25傳輸大文件 344
5.7.26驗證read和write方法是非阻塞的 346
5.8Selector類的使用 348
5.8.1驗證public abstract int select()方法具有阻塞性 350
5.8.2select()方法不阻塞的原因和解決辦法 351
5.8.3出現(xiàn)重復(fù)消費的情況 353
5.8.4使用remove()方法解決重復(fù)消費問題 355
5.8.5驗證產(chǎn)生的set1和set2關(guān)聯(lián)的各自對象一直是同一個 356
5.8.6int selector.select()方法返回值的含義 360
5.8.7從已就緒的鍵集中獲得通道中的數(shù)據(jù) 362
5.8.8對相同的通道注冊不同的相關(guān)事件返回同一個SelectionKey 363
5.8.9判斷選擇器是否為打開狀態(tài) 365
5.8.10獲得SelectorProvider provider對象 365
5.8.11返回此選擇器的鍵集 366
5.8.12public abstract int select(long timeout)方法的使用 367
5.8.13public abstract int selectNow()方法的使用 368
5.8.14喚醒操作 369
5.8.15測試若干細(xì)節(jié) 370
5.9SelectionKey類的使用 380
5.9.1判斷是否允許連接SelectableChannel對象 381
5.9.2判斷是否已準(zhǔn)備好進行讀取 383
5.9.3判斷是否已準(zhǔn)備好進行寫入 384
5.9.4返回SelectionKey關(guān)聯(lián)的選擇器 386
5.9.5在注冊操作時傳入attachment附件 387
5.9.6設(shè)置attachment附件 389
5.9.7獲取與設(shè)置此鍵的interest集合 390
5.9.8判斷此鍵是否有效 392
5.9.9獲取此鍵的ready操作集合 392
5.9.10取消操作 395
5.10DatagramChannel類的使用 396
5.10.1使用DatagramChannel類實現(xiàn)UDP通信 398
5.10.2連接操作 399
5.10.3斷開連接 400
5.10.4將通道加入組播地址 400
5.10.5將通道加入組播地址且接收指定客戶端數(shù)據(jù) 402
5.11Pipe.SinkChannel和Pipe.SourceChannel類的使用 403
5.12SelectorProvider類的使用 406
5.13小結(jié) 407
第6章AIO的使用 408
6.1AsynchronousFileChannel類的使用 408
6.1.1獲取此通道文件的獨占鎖 409
6.1.2獲取通道文件給定區(qū)域的鎖 410
6.1.3實現(xiàn)重疊鎖定 412
6.1.4返回此通道文件當(dāng)前大小與通道打開狀態(tài) 413
6.1.5CompletionHandler接口的使用 413
6.1.6public void failed (Throwable exc, A attachment)方法調(diào)用時機 414
6.1.7執(zhí)行指定范圍的鎖定與傳入附件及整合接口 415
6.1.8執(zhí)行鎖定與傳入附件及整合接口CompletionHandler 416
6.1.9lock (position, size, shared, attachment,CompletionHandler)方法的特點 418
6.1.10讀取數(shù)據(jù)方式1 420
6.1.11讀取數(shù)據(jù)方式2 420
6.1.12寫入數(shù)據(jù)方式1 421
6.1.13寫入數(shù)據(jù)方式2 422
6.2AsynchronousServerSocketChannel和AsynchronousSocketChannel類的使用 422
6.2.1接受方式1 425
6.2.2接受方式2 427
6.2.3重復(fù)讀與重復(fù)寫出現(xiàn)異常 428
6.2.4讀數(shù)據(jù) 429
6.2.5寫數(shù)據(jù) 433
6.3同步、異步、阻塞與非阻塞之間的關(guān)系 436
6.4小結(jié) 437