您好,登錄后才能下訂單哦!
傳統(tǒng)BIO網(wǎng)絡(luò)編程知識點與Java NIO分別是怎樣的,針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
本來想把這部分內(nèi)容加在“Netty高并發(fā)編程與性能調(diào)優(yōu)實戰(zhàn)經(jīng)驗分享”這篇的,但是怕大家看了前這篇的內(nèi)容,就沒有看下去的欲望了,哈哈。
傳統(tǒng)BIO編程知識點總結(jié)
Java NIO簡介
下圖為我用印象筆記所做的《Netty高并發(fā)編程與性能調(diào)優(yōu)》思維導(dǎo)圖。這是我對網(wǎng)絡(luò)編程的總結(jié)吧,我算是很早就開始接觸Socket編程的,在大學(xué)就學(xué)過Socket編程,雖然那時候?qū)W的是C#,但原理是一樣的,不分語言。
我參加過中國軟件杯,做的就是一個“同步手繪板”應(yīng)用,使用Socket實現(xiàn)移動端和PC端同步繪制,雖然沒得獎。??茖嵙?xí)的時候,做過一個監(jiān)控攝像頭設(shè)備的系統(tǒng),比如遠(yuǎn)程控制拍照角度、自動拍照、獲取電量等。從第一家公司辭職之后,也自己做了一個模仿微信的聊天系統(tǒng)。升本期間,了解到有NIO,Netty這些云云的存在,也跟風(fēng)學(xué)了一把,后面畢設(shè)也用Netty實現(xiàn)一個戀愛APP的私密聊天功能的服務(wù)器。對BIO、NIO也算有點了解,最近為了項目的性能調(diào)優(yōu),也啃了好久的Netty的源碼,雖然現(xiàn)在也只看懂了些皮毛,不過對本次性能調(diào)優(yōu)還是非常有幫助的。
我對傳統(tǒng)BIO編程的一點總結(jié),幾個我認(rèn)為最重要的知識點。
知識點一:Socket套接字復(fù)用池
不管任何一門高級語言,Socket編程都是服務(wù)端一個線程處理客戶端的一個連接,因為讀寫都是阻塞的。為避免頻繁的線程創(chuàng)建和消毀,都會使用線程池來實現(xiàn)線程的復(fù)用。對于BIO,一邊會根據(jù)服務(wù)器硬件配置估算服務(wù)所能并發(fā)處理的最大連接數(shù),據(jù)此設(shè)置線程復(fù)用池的大小。
知識點二:內(nèi)存緩存池
用于接收和發(fā)送字節(jié)數(shù)據(jù)的緩存區(qū),也是用于避免頻繁向系統(tǒng)申請和釋放內(nèi)存。對應(yīng)的,Netty也有緩存池的概念,相對復(fù)雜些,分直接內(nèi)存和堆內(nèi)存兩種,直接內(nèi)存就是jvm堆外內(nèi)存,不被jvm所管。
知識點三:消息隊列,解析數(shù)據(jù)包
有了內(nèi)存緩存池,為啥還要有個消息隊列。服務(wù)端讀取到客戶端發(fā)送過來的消息,可能不是一個完整的數(shù)據(jù)包,所以就需要對接收到的字節(jié)數(shù)據(jù)做解析,根據(jù)所使用的協(xié)議去解析字節(jié)數(shù)據(jù),解析成一個個完整的數(shù)據(jù)包。
知識點四:自定義通信協(xié)議
做為后端開發(fā)人員,我們最熟悉不過的就是HTTP協(xié)議了。使用Socket編寫網(wǎng)絡(luò)程序,我們可以自定義通信協(xié)議,這相當(dāng)?shù)暮猛?。自定義協(xié)議可以避免別人識別你的通信協(xié)議攔截數(shù)據(jù)包分析,也可對數(shù)據(jù)包進(jìn)行加密傳輸。自定義協(xié)議的數(shù)據(jù)包體積小,可跟據(jù)業(yè)務(wù)需求修改。
知識點五:心跳?;?br/>
NIO與BIO的區(qū)別:
BIO: 同步阻塞式IO,服務(wù)器需要為每一個客戶端創(chuàng)建一個線程處理連接。
NIO:同步非阻塞式IO,服務(wù)端可以使用一個或多個線程監(jiān)聽客戶端的連接請求,并將連接注冊到多路復(fù)用器Selector上,使用Selector輪詢I/O就緒事件,當(dāng)監(jiān)聽到有就緒事件時,才會為準(zhǔn)備就緒的連接開啟一個線程去處理。
NIO
Channel:channel是一個通道,可以通過它讀取和寫入數(shù)據(jù)。對于網(wǎng)絡(luò)編程而言,網(wǎng)絡(luò)數(shù)據(jù)通過channel接受客戶端發(fā)來的消息,也可以通過channel向客戶端發(fā)送消息,channel是全雙工的,對應(yīng)的類分別為SocketChannel、ServerSocketChannel。
ServerSocketChannel: 用于監(jiān)聽TCP連接的通道,類似于ServerSocket。
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 綁定服務(wù)端監(jiān)聽端口serverSocketChannel.socket().bind(new InetSocketAddress(this.port), 1024);// 監(jiān)聽客戶端連接SocketChannel socketChannel = serverSocketChannel.accept();
SocketChannel:用于TCP網(wǎng)絡(luò)連接的通道。實現(xiàn)與客戶端數(shù)據(jù)傳輸??梢栽O(shè)置為非阻塞。類似于Socket。
Socket于Channel的區(qū)別:socket數(shù)據(jù)流是單向的,客戶端與服務(wù)器實現(xiàn)雙向通信需要一個Input流和一個Output流,一個用于接收數(shù)據(jù),一個用于發(fā)送數(shù)據(jù)。而Channel是全雙工的,即可以接受客戶端發(fā)來的數(shù)據(jù),也可以向客戶端發(fā)送數(shù)據(jù)。
Selector:選擇器,或多路復(fù)用器。用于輪詢檢查一個或多個NIO 通道(Channel)的狀態(tài)。對于網(wǎng)絡(luò)編程而言,Socket有四種狀態(tài),監(jiān)聽連接、連接準(zhǔn)備就緒、讀準(zhǔn)備就緒、寫準(zhǔn)備就緒,對應(yīng)的SelectorKey的取值如下。
SelectorKey:
OP_READ = 1 << 0; 0000 0001OP_WRITE = 1 << 2; 0000 0100OP_CONNECT = 1 << 3; 0000 1000OP_ACCEPT = 1 << 4; 0001 0000
I/O多路復(fù)用:I/O指的是網(wǎng)絡(luò)I/O,多路指多個TCP連接(BIO: socket, NIO:channel),復(fù)用指的是只用一個或多個線程處理事件??偟膩碚f,就是使用一個或多個線程處理多個TCP連接。不再像BIO的一個連接一個線程處理,NIO則可以只用一個線程處理所有連接,也可以使用n個線程處理所有連接。
Channel通過register方法與Selector多路復(fù)用器綁定,并指定自己感興趣的事件,比如
channel.configureBlocking(false);SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
綁定后生成一個SelectionKey,SelectionKey持有Channel。
通過輪詢監(jiān)聽,通過Selector的select()方法可以選擇已經(jīng)準(zhǔn)備就緒的通道,這些通道包含你注冊的事件。比如你對讀、寫就緒的通道感興趣,那么select()方法就會返回讀事件已經(jīng)就緒的那些通道和寫事件已經(jīng)就緒的那些通道。select方法是一個阻塞方法,至少有一個通道在你注冊的事件準(zhǔn)備就緒時,才會返回。返回結(jié)果為準(zhǔn)備就緒的SelectionKey總數(shù)。
當(dāng)監(jiān)聽到有事件準(zhǔn)備就緒時,再通過Selector的selectedKeys()獲取準(zhǔn)備就緒的SelectionKey集合。通過遍歷處理事件。處理完后需要移除,否則下次selectedKeys()還會重復(fù)拿到。
for (;;) { try { // 獲取到之后返回總數(shù),否則線程將處于阻塞狀態(tài) int readyCount = this.selector.select(); if (readyCount == 0){ continue; } // 獲取當(dāng)前所有準(zhǔn)備就緒的SelectionKey Set<SelectionKey> readyKeys = this.selector.selectedKeys(); for (SelectionKey selectionKey : readyKeys) { // 需要注冊新的感興趣事件 handleEvent(selectionKey); // 處理完要移除,否則下次selectedKeys還是能拿到 readyKeys.remove(selectionKey); } } catch (IOException e) { e.printStackTrace(); }}
select方法底層通過調(diào)用native方法實現(xiàn)事件監(jiān)聽,在linux上,就是調(diào)用系統(tǒng)的epoll方法,網(wǎng)卡設(shè)備對應(yīng)一個中斷信號, 當(dāng)網(wǎng)卡收到網(wǎng)絡(luò)端的消息的時候會向CPU發(fā)起中斷請求, 然后CPU處理該請求。通過驅(qū)動程序進(jìn)而操作系統(tǒng)得到通知,系統(tǒng)再通知epoll,epoll通知用戶代碼。
關(guān)于傳統(tǒng)BIO網(wǎng)絡(luò)編程知識點與Java NIO分別是怎樣的問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。