1. 程式人生 > >《Netty 權威指南》—— NIO客戶端序列圖

《Netty 權威指南》—— NIO客戶端序列圖

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

步驟一:開啟SocketChannel,繫結客戶端本地地址(可選,預設系統會隨機分配一個可用的本地地址),示例程式碼如下:

SocketChannel clientChannel = SocketChannel.open();

步驟二:設定SocketChannel為非阻塞模式,同時設定客戶端連線的TCP引數,示例程式碼如下:

clientChannel.configureBlocking(false);
socket.setReuseAddress(true);
socket.setReceiveBufferSize(BUFFER_SIZE);
socket.setSendBufferSize(BUFFER_SIZE);

步驟三:非同步連線服務端,示例程式碼如下:

boolean connected = clientChannel.connect(new InetSocketAddress(“ip”,port));

步驟四:判斷是否連線成功,如果連線成功,則直接註冊讀狀態位到多路複用器中,如果當前沒有連線成功(非同步連線,返回false,說明客戶端已經發送sync包,服務端沒有返回ack包,物理鏈路還沒有建立),示例程式碼如下:

if (connected) 
{
	clientChannel.register( selector, SelectionKey.OP_READ, ioHandler);
}
else
{
    clientChannel.register( selector, SelectionKey.OP_CONNECT, ioHandler);
}


步驟五:向Reactor執行緒的多路複用器註冊OP_CONNECT狀態位,監聽服務端的TCP ACK應答,示例程式碼如下:

clientChannel.register( selector, SelectionKey.OP_CONNECT, ioHandler);

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

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

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

int num = selector.select();
Set selectedKeys = selector.selectedKeys();
Iterator it = selectedKeys.iterator();
while (it.hasNext()) {
if (key.isConnectable())
  //handlerConnect(); 
}

步驟九:判斷連線結果,如果連線成功,註冊讀事件到多路複用器,示例程式碼如下:

if (channel.finishConnect())
  registerRead();

步驟十:註冊讀事件到多路複用器:

clientChannel.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);

通過序列圖和關鍵程式碼的解說,相信大家對建立NIO客戶端程式有了一個初步的瞭解,下面,就跟隨著我們的腳步繼續看看如果使用NIO改造之前的時間伺服器客戶端TimeClient。

1

NIO客戶端建立序列圖