Java NIO學(xué)習(xí)筆記 - NIO服務(wù)端時(shí)序圖

NIO服務(wù)端通信序列圖如下:

1.png

下面,我們對(duì)NIO服務(wù)端的主要?jiǎng)?chuàng)建過(guò)程進(jìn)行講解和說(shuō)明:

步驟一:打開(kāi)ServerSocketChannel,用于監(jiān)聽(tīng)客戶(hù)端的連接,它是所有客戶(hù)端連接的父管道,代碼示例如下:

ServerSocketChannel acceptorSvr = ServerSocketChannel.open();

步驟二:綁定監(jiān)聽(tīng)端口,設(shè)置連接為非阻塞模式,示例代碼如下:

acceptorSvr.socket().bind(new InetSocketAddress(InetAddress.getByName("IP"),port));
acceptorSvr.configureBlocking(false);

步驟三:創(chuàng)建Reactor線程,創(chuàng)建多路復(fù)用器并啟動(dòng)線程,代碼如下:

Selector selector = Selector.open();
New Thread(new ReactorTask()).start();

步驟四:將ServerSocketChannel注冊(cè)到Reactor線程的多路復(fù)用器Selector上,監(jiān)聽(tīng)ACCEPT事件,代碼如下:

SelectionKey key = acceptorSvr.register(selector,SelectionKey.OP_ACCEPT,ioHandler);

步驟五:多路復(fù)用器在線程run方法的無(wú)限循環(huán)體內(nèi)輪詢(xún)準(zhǔn)備就緒的Key,代碼如下:

int num = selector.select();
Set selectedKey s = selector.selectedKeys();
Iterator it = selectedKeys.iterator();
while(it.hasNext()){
    SelectionKey key = (SelectionKey)it.next();
    // ... deal with I/O event ...
}

步驟六:多路復(fù)用器監(jiān)聽(tīng)到有新的客戶(hù)端接入,處理新的接入請(qǐng)求,完成TCP三次握手,建立物理鏈路,代碼示例如下:

SocketChannel channel = svrChannel.accept();

步驟七:設(shè)置客戶(hù)端鏈路為非阻塞模式,示例代碼如下:

channel.configureBlocking(false);
channel.socket().setReuseAddress(true);
......

步驟八:將新接入的客戶(hù)端連接注冊(cè)到Reactor線程的多路復(fù)用器上,監(jiān)聽(tīng)讀操作,用來(lái)讀取客戶(hù)端發(fā)送的網(wǎng)絡(luò)消息,代碼如下:

SelectionKey  key = socketChannel.register(selector,SelectionKey.OP_READ);

步驟九:異步讀取客戶(hù)端請(qǐng)求消息到緩沖區(qū),示例代碼如下:

int readNumber = channel.read(recelvedBuffer);

步驟十:對(duì)ByteBuffer進(jìn)行編解碼,如果有半包消息指針reset,繼續(xù)讀取后續(xù)的報(bào)文,將解碼成功的消息封裝成Task,投遞到業(yè)務(wù)線程池中,進(jìn)行業(yè)務(wù)邏輯編排,示例代碼如下:

Object message = null;
while(buffer.hasRemain()){
    byteBuffer.mark();
    Object message = decode(byteBuffer);
    if(message == null){
        byteBuffer.reset();
        break;
    }
    messageList.add(message);
}
if(!byteBuffer.hasRemain())
    byteBuffer.clear();
else
    byteBuffer.compact();
if(messageList != null & !messageList.isEmpty()){
    for(Object messageE :messageList)
        handlerTask(messageE);
}

步驟十一:將POJO對(duì)象encode成ByteBuffer,調(diào)用SocketChannel的異步write方法,將消息異步發(fā)送給客戶(hù)端,示例代碼如下:

socketChannel.write(buffer);

注意:如果發(fā)送區(qū)TCP緩沖區(qū)滿(mǎn),會(huì)導(dǎo)致寫(xiě)半包,此時(shí),需要注冊(cè)監(jiān)聽(tīng)寫(xiě)操作位,循環(huán)寫(xiě),直到整包消息寫(xiě)入TCP緩沖區(qū)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容