NIO服務端通訊序列圖以下:java
下面,咱們對NIO服務端的主要建立過程進行講解和說明:網絡
步驟一:打開ServerSocketChannel,用於監聽客戶端的鏈接,它是全部客戶端鏈接的父管道,代碼示例以下:異步
ServerSocketChannel acceptorSvr = ServerSocketChannel.open();
步驟二:綁定監聽端口,設置鏈接爲非阻塞模式,示例代碼以下:socket
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,代碼以下:code
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 ... }
步驟六:多路複用器監聽到有新的客戶端接入,處理新的接入請求,完成TCP三次握手,創建物理鏈路,代碼示例以下:對象
SocketChannel channel = svrChannel.accept();
步驟七:設置客戶端鏈路爲非阻塞模式,示例代碼以下:事件
channel.configureBlocking(false); channel.socket().setReuseAddress(true); ......
步驟八:將新接入的客戶端鏈接註冊到Reactor線程的多路複用器上,監聽讀操做,用來讀取客戶端發送的網絡消息,代碼以下:get
SelectionKey key = socketChannel.register(selector,SelectionKey.OP_READ);
步驟九:異步讀取客戶端請求消息到緩衝區,示例代碼以下:
int readNumber = channel.read(recelvedBuffer);
步驟十:對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緩衝區。