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

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

1.png

下面,我們對NIO服務(wù)端的主要創(chuàng)建過程進(jìn)行講解和說明:

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

ServerSocketChannel acceptorSvr = ServerSocketChannel.open();

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

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

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

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

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

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

步驟五:多路復(fù)用器在線程run方法的無限循環(huán)體內(nèi)輪詢準(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)聽到有新的客戶端接入,處理新的接入請求,完成TCP三次握手,建立物理鏈路,代碼示例如下:

SocketChannel channel = svrChannel.accept();

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

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

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

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

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

int readNumber = channel.read(recelvedBuffer);

步驟十:對ByteBuffer進(jìn)行編解碼,如果有半包消息指針reset,繼續(xù)讀取后續(xù)的報文,將解碼成功的消息封裝成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對象encode成ByteBuffer,調(diào)用SocketChannel的異步write方法,將消息異步發(fā)送給客戶端,示例代碼如下:

socketChannel.write(buffer);

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

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

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

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