傳統(tǒng)BIO網(wǎng)絡(luò)編程知識(shí)點(diǎn)與Java NIO分別是怎樣的,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。
仙游網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)公司!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、響應(yīng)式網(wǎng)站開(kāi)發(fā)等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。成都創(chuàng)新互聯(lián)公司成立與2013年到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專(zhuān)注于網(wǎng)站建設(shè)就選成都創(chuàng)新互聯(lián)公司。
本來(lái)想把這部分內(nèi)容加在“Netty高并發(fā)編程與性能調(diào)優(yōu)實(shí)戰(zhàn)經(jīng)驗(yàn)分享”這篇的,但是怕大家看了前這篇的內(nèi)容,就沒(méi)有看下去的欲望了,哈哈。
傳統(tǒng)BIO編程知識(shí)點(diǎn)總結(jié)
Java NIO簡(jiǎn)介
下圖為我用印象筆記所做的《Netty高并發(fā)編程與性能調(diào)優(yōu)》思維導(dǎo)圖。這是我對(duì)網(wǎng)絡(luò)編程的總結(jié)吧,我算是很早就開(kāi)始接觸Socket編程的,在大學(xué)就學(xué)過(guò)Socket編程,雖然那時(shí)候?qū)W的是C#,但原理是一樣的,不分語(yǔ)言。
我參加過(guò)中國(guó)軟件杯,做的就是一個(gè)“同步手繪板”應(yīng)用,使用Socket實(shí)現(xiàn)移動(dòng)端和PC端同步繪制,雖然沒(méi)得獎(jiǎng)。專(zhuān)科實(shí)習(xí)的時(shí)候,做過(guò)一個(gè)監(jiān)控?cái)z像頭設(shè)備的系統(tǒng),比如遠(yuǎn)程控制拍照角度、自動(dòng)拍照、獲取電量等。從第一家公司辭職之后,也自己做了一個(gè)模仿微信的聊天系統(tǒng)。升本期間,了解到有NIO,Netty這些云云的存在,也跟風(fēng)學(xué)了一把,后面畢設(shè)也用Netty實(shí)現(xiàn)一個(gè)戀愛(ài)APP的私密聊天功能的服務(wù)器。對(duì)BIO、NIO也算有點(diǎn)了解,最近為了項(xiàng)目的性能調(diào)優(yōu),也啃了好久的Netty的源碼,雖然現(xiàn)在也只看懂了些皮毛,不過(guò)對(duì)本次性能調(diào)優(yōu)還是非常有幫助的。
我對(duì)傳統(tǒng)BIO編程的一點(diǎn)總結(jié),幾個(gè)我認(rèn)為最重要的知識(shí)點(diǎn)。
知識(shí)點(diǎn)一:Socket套接字復(fù)用池
不管任何一門(mén)高級(jí)語(yǔ)言,Socket編程都是服務(wù)端一個(gè)線(xiàn)程處理客戶(hù)端的一個(gè)連接,因?yàn)樽x寫(xiě)都是阻塞的。為避免頻繁的線(xiàn)程創(chuàng)建和消毀,都會(huì)使用線(xiàn)程池來(lái)實(shí)現(xiàn)線(xiàn)程的復(fù)用。對(duì)于BIO,一邊會(huì)根據(jù)服務(wù)器硬件配置估算服務(wù)所能并發(fā)處理的最大連接數(shù),據(jù)此設(shè)置線(xiàn)程復(fù)用池的大小。
知識(shí)點(diǎn)二:內(nèi)存緩存池
用于接收和發(fā)送字節(jié)數(shù)據(jù)的緩存區(qū),也是用于避免頻繁向系統(tǒng)申請(qǐng)和釋放內(nèi)存。對(duì)應(yīng)的,Netty也有緩存池的概念,相對(duì)復(fù)雜些,分直接內(nèi)存和堆內(nèi)存兩種,直接內(nèi)存就是jvm堆外內(nèi)存,不被jvm所管。
知識(shí)點(diǎn)三:消息隊(duì)列,解析數(shù)據(jù)包
有了內(nèi)存緩存池,為啥還要有個(gè)消息隊(duì)列。服務(wù)端讀取到客戶(hù)端發(fā)送過(guò)來(lái)的消息,可能不是一個(gè)完整的數(shù)據(jù)包,所以就需要對(duì)接收到的字節(jié)數(shù)據(jù)做解析,根據(jù)所使用的協(xié)議去解析字節(jié)數(shù)據(jù),解析成一個(gè)個(gè)完整的數(shù)據(jù)包。
知識(shí)點(diǎn)四:自定義通信協(xié)議
做為后端開(kāi)發(fā)人員,我們最熟悉不過(guò)的就是HTTP協(xié)議了。使用Socket編寫(xiě)網(wǎng)絡(luò)程序,我們可以自定義通信協(xié)議,這相當(dāng)?shù)暮猛?。自定義協(xié)議可以避免別人識(shí)別你的通信協(xié)議攔截?cái)?shù)據(jù)包分析,也可對(duì)數(shù)據(jù)包進(jìn)行加密傳輸。自定義協(xié)議的數(shù)據(jù)包體積小,可跟據(jù)業(yè)務(wù)需求修改。
知識(shí)點(diǎn)五:心跳?;?/p>TCP協(xié)議,需三次握手才建立連接,需四次揮手才釋放連接。但避免不了的是客戶(hù)端或是服務(wù)器意外斷開(kāi)連接,而對(duì)方并不知道。比如客戶(hù)端蹭隔壁老王的Wifi被發(fā)現(xiàn)了…。如果客戶(hù)端意外斷開(kāi)后,服務(wù)端還往客戶(hù)端寫(xiě)消息,就會(huì)拋出異常。如果長(zhǎng)時(shí)間沒(méi)有讀寫(xiě)數(shù)據(jù),那線(xiàn)程一直會(huì)阻塞在那,占用線(xiàn)程。心跳包除了能檢測(cè)連接是否可用外,還可實(shí)現(xiàn)斷開(kāi)自動(dòng)重新連接。
在某些業(yè)務(wù)場(chǎng)景下,我們可以設(shè)置,當(dāng)連接多久沒(méi)有讀寫(xiě)過(guò)數(shù)據(jù)時(shí),服務(wù)端主動(dòng)斷開(kāi)連接。這就是空閑檢測(cè)。NIO與BIO的區(qū)別:
BIO: 同步阻塞式IO,服務(wù)器需要為每一個(gè)客戶(hù)端創(chuàng)建一個(gè)線(xiàn)程處理連接。
NIO:同步非阻塞式IO,服務(wù)端可以使用一個(gè)或多個(gè)線(xiàn)程監(jiān)聽(tīng)客戶(hù)端的連接請(qǐng)求,并將連接注冊(cè)到多路復(fù)用器Selector上,使用Selector輪詢(xún)I/O就緒事件,當(dāng)監(jiān)聽(tīng)到有就緒事件時(shí),才會(huì)為準(zhǔn)備就緒的連接開(kāi)啟一個(gè)線(xiàn)程去處理。
NIO與傳統(tǒng)的BIO模型相比,節(jié)省了為每個(gè)連接綁定一個(gè)線(xiàn)程的開(kāi)銷(xiāo),支持同時(shí)與大量的客戶(hù)端建立連接,而只受限于系統(tǒng)最大打開(kāi)文件描述符的數(shù)量。NIO
Channel:channel是一個(gè)通道,可以通過(guò)它讀取和寫(xiě)入數(shù)據(jù)。對(duì)于網(wǎng)絡(luò)編程而言,網(wǎng)絡(luò)數(shù)據(jù)通過(guò)channel接受客戶(hù)端發(fā)來(lái)的消息,也可以通過(guò)channel向客戶(hù)端發(fā)送消息,channel是全雙工的,對(duì)應(yīng)的類(lèi)分別為SocketChannel、ServerSocketChannel。
ServerSocketChannel: 用于監(jiān)聽(tīng)TCP連接的通道,類(lèi)似于ServerSocket。
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 綁定服務(wù)端監(jiān)聽(tīng)端口serverSocketChannel.socket().bind(new InetSocketAddress(this.port), 1024);// 監(jiān)聽(tīng)客戶(hù)端連接SocketChannel socketChannel = serverSocketChannel.accept();
SocketChannel:用于TCP網(wǎng)絡(luò)連接的通道。實(shí)現(xiàn)與客戶(hù)端數(shù)據(jù)傳輸??梢栽O(shè)置為非阻塞。類(lèi)似于Socket。
Socket于Channel的區(qū)別:socket數(shù)據(jù)流是單向的,客戶(hù)端與服務(wù)器實(shí)現(xiàn)雙向通信需要一個(gè)Input流和一個(gè)Output流,一個(gè)用于接收數(shù)據(jù),一個(gè)用于發(fā)送數(shù)據(jù)。而Channel是全雙工的,即可以接受客戶(hù)端發(fā)來(lái)的數(shù)據(jù),也可以向客戶(hù)端發(fā)送數(shù)據(jù)。
Selector:選擇器,或多路復(fù)用器。用于輪詢(xún)檢查一個(gè)或多個(gè)NIO 通道(Channel)的狀態(tài)。對(duì)于網(wǎng)絡(luò)編程而言,Socket有四種狀態(tài),監(jiān)聽(tīng)連接、連接準(zhǔn)備就緒、讀準(zhǔn)備就緒、寫(xiě)準(zhǔn)備就緒,對(duì)應(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,多路指多個(gè)TCP連接(BIO: socket, NIO:channel),復(fù)用指的是只用一個(gè)或多個(gè)線(xiàn)程處理事件??偟膩?lái)說(shuō),就是使用一個(gè)或多個(gè)線(xiàn)程處理多個(gè)TCP連接。不再像BIO的一個(gè)連接一個(gè)線(xiàn)程處理,NIO則可以只用一個(gè)線(xiàn)程處理所有連接,也可以使用n個(gè)線(xiàn)程處理所有連接。
Channel通過(guò)register方法與Selector多路復(fù)用器綁定,并指定自己感興趣的事件,比如
channel.configureBlocking(false);SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
綁定后生成一個(gè)SelectionKey,SelectionKey持有Channel。
通過(guò)輪詢(xún)監(jiān)聽(tīng),通過(guò)Selector的select()方法可以選擇已經(jīng)準(zhǔn)備就緒的通道,這些通道包含你注冊(cè)的事件。比如你對(duì)讀、寫(xiě)就緒的通道感興趣,那么select()方法就會(huì)返回讀事件已經(jīng)就緒的那些通道和寫(xiě)事件已經(jīng)就緒的那些通道。select方法是一個(gè)阻塞方法,至少有一個(gè)通道在你注冊(cè)的事件準(zhǔn)備就緒時(shí),才會(huì)返回。返回結(jié)果為準(zhǔn)備就緒的SelectionKey總數(shù)。
當(dāng)監(jiān)聽(tīng)到有事件準(zhǔn)備就緒時(shí),再通過(guò)Selector的selectedKeys()獲取準(zhǔn)備就緒的SelectionKey集合。通過(guò)遍歷處理事件。處理完后需要移除,否則下次selectedKeys()還會(huì)重復(fù)拿到。
for (;;) { try { // 獲取到之后返回總數(shù),否則線(xiàn)程將處于阻塞狀態(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) { // 需要注冊(cè)新的感興趣事件 handleEvent(selectionKey); // 處理完要移除,否則下次selectedKeys還是能拿到 readyKeys.remove(selectionKey); } } catch (IOException e) { e.printStackTrace(); }}
select方法底層通過(guò)調(diào)用native方法實(shí)現(xiàn)事件監(jiān)聽(tīng),在linux上,就是調(diào)用系統(tǒng)的epoll方法,網(wǎng)卡設(shè)備對(duì)應(yīng)一個(gè)中斷信號(hào), 當(dāng)網(wǎng)卡收到網(wǎng)絡(luò)端的消息的時(shí)候會(huì)向CPU發(fā)起中斷請(qǐng)求, 然后CPU處理該請(qǐng)求。通過(guò)驅(qū)動(dòng)程序進(jìn)而操作系統(tǒng)得到通知,系統(tǒng)再通知epoll,epoll通知用戶(hù)代碼。
關(guān)于傳統(tǒng)BIO網(wǎng)絡(luò)編程知識(shí)點(diǎn)與Java NIO分別是怎樣的問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。
文章標(biāo)題:傳統(tǒng)BIO網(wǎng)絡(luò)編程知識(shí)點(diǎn)與JavaNIO分別是怎樣的
文章鏈接:http://jinyejixie.com/article14/posode.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、移動(dòng)網(wǎng)站建設(shè)、品牌網(wǎng)站制作、虛擬主機(jī)、面包屑導(dǎo)航、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
全網(wǎng)營(yíng)銷(xiāo)推廣知識(shí)