Java NOI非阻塞技術不是開啟線程去等待端口的響應,而是采用Reactor模式或Observer模式監聽I/O端口,當端口有響應時,會自動通知我們,從而實現流暢的I/O讀寫。
Java NOI中selector可視為一個觀察者,只要我們把要觀察的SocketChannel告訴Selector(注冊的方式),我們就可以做其余的事情,等到已告知Channel上有事情發生時,Selector會通知我們,傳回一組SelectionKey,我們讀取這些Key,就可以獲得Channel上的數據了。
Client端的底層通信直接采用了阻塞式IO編程,Server是采用Java NIO機制進行RPC通信:
Java NIO參考資料:
http://www.linuxidc.com/Linux/2012-06/62080.htm
http://www.linuxidc.com/Linux/2012-06/62079.htm
Server是一個abstract類,抽象之處在call方法中,RPC.Server是ipc.Server的實現類,RPC.Server的構造函數調用了ipc.Server類的構造函數的,Namenode在初始化時調用RPC.getServer方法初始化了RPC.Server:
public static Server getServer(final Object instance, final String bindAddress, final int port,
final int numHandlers,
final boolean verbose, Configuration conf,
SecretManager<? extends TokenIdentifier> secretManager)
throws IOException {
return new Server(instance, conf, bindAddress, port, numHandlers, verbose, secretManager);
}
Server.Call是一個請求類,類似Client.Call,只是添加了Call的時間戳機制:
private static class Call {
private int id; // 請求id
private Writable param; // 請求的參數
private Connection connection; // 和Client一樣,表示一個C/S間的連接
private long timestamp; // 時間戳
private ByteBuffer response; // server對此次請求的響應結果
...
}
知道了Client.Connection後,顯然Server.Connection就是Server到Client的連接。Server.Connection內保存了Client的地址,用於災難恢復。Server.Connection通過調用readAndProcess對Client進行一些操作:版本校驗,讀數據頭processHeader(獲取通信協議protocol,根據頭部的ugi信息創建user對象)以及讀數據processData(獲取Client發送過來的Call.id和params,根據二者建立一個請求call,並將請求call入隊callQueue)【readAndProcess方法是在Listener.doRead時調用,此時監聽器監聽到新連接的讀數據事件】。