1. 程式人生 > >RMI執行過程分析

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端的請求後,會做三件事:

  1. unmarshals 客戶端傳送來的資料
  2. 根據收到的資料,執行相關的方法,拿到執行結果
  3. marshals執行結果,傳送給client

Stub:執行在client端,需要呼叫遠端方法時,會做下面幾件事(基本和skeleton反著來)

  1. marshals待發送資料併發送
  2. 等待結果
  3. 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在處理請求的時候,是不是這樣子處理收到的資料和傳送資料的?