1. 程式人生 > >《Netty 權威指南》—— 服務端序列圖

《Netty 權威指南》—— 服務端序列圖

宣告:本文是《Netty 權威指南》的樣章,感謝博文視點授權併發程式設計網站釋出樣章,

下面,我們對NIO服務端的主要建立過程進行講解和說明,作為NIO的基礎入門,我們將忽略掉一些在生產環境中部署所需要的一些特性和功能。

步驟一:開啟ServerSocketChannel,用於監聽客戶端的連線,它是所有客戶端連線的父管道,程式碼示例如下:

ServerSocketChannel acceptorSvr = ServerSocketChannel.open();

步驟二:繫結監聽埠,設定連線為非阻塞模式,示例程式碼如下:

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

步驟三:建立Reactor執行緒,建立多路複用器並啟動執行緒,程式碼如下:

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

步驟四:將ServerSocketChannel註冊到Reactor執行緒的多路複用器Selector上,監聽ACCEPT事件,程式碼如下:

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

步驟五:多路複用器線上程run方法的無限迴圈體內輪詢準備就緒的Key,程式碼如下:

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

步驟六:多路複用器監聽到有新的客戶端接入,處理新的接入請求,完成TCP三次握手,建立物理鏈路,程式碼示例如下:

SocketChannel channel = svrChannel.accept();

步驟七:設定客戶端鏈路為非阻塞模式,示例程式碼如下:

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

步驟八:將新接入的客戶端連線註冊到Reactor執行緒的多路複用器上,監聽讀操作,用來讀取客戶端傳送的網路訊息,程式碼如下:

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

步驟九:非同步讀取客戶端請求訊息到緩衝區,示例程式碼如下:

int  readNumber =  channel.read(receivedBuffer);

步驟十:對ByteBuffer進行編解碼,如果有半包訊息指標reset,繼續讀取後續的報文,將解碼成功的訊息封裝成Task,投遞到業務執行緒池中,進行業務邏輯編排,示例程式碼如下:

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,呼叫SocketChannel的非同步write介面,將訊息非同步傳送給客戶端,示例程式碼如下:

socketChannel.write(buffer);

注意:如果傳送區TCP緩衝區滿,會導致寫半包,此時,需要註冊監聽寫操作位,迴圈寫,直到整包訊息寫入TCP緩衝區,此處不贅述,後續Netty原始碼分析章節會詳細分析Netty的處理策略。
當我們瞭解建立NIO服務端的基本步驟之後,下面我們將前面的時間伺服器程式通過NIO重寫一遍,讓大家能夠學習到完整版的NIO服務端建立。

1

NIO服務端通訊序列圖