《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。