RMI執行過程分析
客戶端程式碼
public class RMIClient {
public static void main(String... args) throws RemoteException, NotBoundException, MalformedURLException {
if (args == null || args.length <= 1) {
System.out.println("usage : java -jar RMIClient.jar rmi_server_ip content");
System.exit(0 );
}
IRMIService service = (IRMIService) Naming.lookup("rmi://"+args[0]+":1099/RMIServer");
System.out.println(service.speakToYourself(args[1]));
//speakToYourself 這個方法僅僅就是在輸入引數前面加上了另外一個字串而已,然後返回。
}
}
抓包結果
上述程式碼執行過程中,使用wireshark進行抓包,得到如下結果
抓包結果分析:
48-49 :tcp的三次握手
54-69 :通訊資料
70-72 :斷開連線
54-69中協議型別凡是tcp的,都是確認其他資料包的確認包,比如55號:
其他為rmi協議的才包含通訊資料。
矛盾
oracle文件中介紹rmi的背景時說:
截圖
socket要求client和server參與到應用層協議,以便對交換的資訊進行編碼和解碼。這種協議的制定就是笨重的和容易出錯的。
官方連線:https://docs.oracle.com/javase/8/docs/platform/rmi/spec/rmi-intro2.html
但是跟蹤rmi原始碼可以知道,rmi同樣時通過socket來通訊的。所以這讓人感覺有點矛盾。。
原始碼截圖
Connection封裝
通過socket拿到Connection後,rmi對conn進行了tcpconnection的封裝
寫入rmi協議頭部資訊
對照抓取到的包資訊:
兩者是符合的。
原理分析
rmi底層採用了Stub 和 Skeletons機制。。
Skeletons:執行在server端,負責分發請求。接到client端的請求後,會做三件事:
- unmarshals 客戶端傳送來的資料
- 根據收到的資料,執行相關的方法,拿到執行結果
- marshals執行結果,傳送給client
Stub:執行在client端,需要呼叫遠端方法時,會做下面幾件事(基本和skeleton反著來)
- marshals待發送資料併發送
- 等待結果
- unmarshals收到的資料
個人認為那個skeletons就有點類似於spring的dispatcherservlet,當收到客戶端請求後,負責把請求分發到相應的controller進行處理。
針對上面給出的客戶端程式碼,客戶端傳送的資料就是 :
"rmi://"+args[0]+":1099/RMIServer"
接收到的結果就是:
IRMIService service //這樣一個例項
注意
拿到 IRMIService service 這樣一個例項後,當呼叫service的 service.speakToYourself(args[1])方法時,並沒有與伺服器通訊。
也就是說這個方法的執行是在本地執行,而非在遠端伺服器上執行後再回傳結果
注意,是 本地執行
那麼rmi說的遠端呼叫,怎麼體現遠端呢?
這個遠端呼叫指的是,客戶端傳送”rmi://”+args[0]+”:1099/RMIServer”到獲取service例項的過程,這個是在遠端伺服器上執行的。
本質
跟蹤程式碼執行過程可以知道,從客戶端傳送資料,到拿到service例項的過程,其實就是
物件的序列號–>網路傳輸–>反序列化 的過程
底層採用的IO模型
檢視原始碼可以知道,現在的rmi實現採用的io是bio,並沒有採用jdk1.4提供的nio功能。看截圖:
PS:我使用的jdk是1.8版本的
JDK8版本及以前版本,RMI採用的IO模型是 BIO
其他
檢視tcp報文段首部的格式,發現並沒有一個標示來標示tcp上層採用的是什麼協議,所以凡是需要用到在tcp協議之上的協議時,都需要自己來處理獲取到的資料,自己根據需要按照某種協議格式進行處理資料。
(PS:IP資料報首部是有這樣的8bit的空間來標示上一層協議是什麼協議)
也就是說當我們拿到通過tcp層傳上來的資料時,需要我們自己按照某種協議的格式去處理資料
好比上面rmi協議,可以發現傳送資料的時候,是程式自己完成寫rmi首部欄位工作的。
所以使用http協議時,也需要自己完成 寫首部,收到資料後分析處理首部等工作。既然如此,可以驗證下tomcat在處理請求的時候,是不是這樣子處理收到的資料和傳送資料的?