天天看點

深入剖析 Java RMI 技術實作原理

RMI(Remote Method Invocation)遠端方法調用是 java 的核心技術之一。是 Enterprise JavaBeans 的基礎技術,是 java 建立分布式應用程式的強大支柱。

RMI 允許一個應用程式通路另外一個伺服器或虛拟機上的對象,方法和服務,它使遠端方法調用就像在本地調用一樣簡單。它為使用者屏蔽了底層的網絡傳輸細節,使用的時候隻需适當處理異常即可。是以 RMI 是非常容易使用的,但同時是非常強大的。

RMI 協定的資料序列化目前支援以下兩種模式:

1.基于 JDK 本身的對象序列化

2.基于 HTTP 協定的資料序列化

協定資料序列化原文說明如下:

The RMI protocol makes use of two other protocols for its on-the-wire format: Java Object Serialization and HTTP. The Object Serialization protocol is used to marshal call and return data. The HTTP protocol is used to "POST" a remote method invocation and obtain return data when circumstances warrant. Each protocol is documented as a separate grammar. Nonterminal symbols in production rules may refer to rules governed by another protocol (either Object Serialization or HTTP). When a protocol boundary is crossed, subsequent productions use that embedded protocol.

[quote]

資料傳輸資料包一共分兩種,一種是資料輸出流,另一種是資料輸入流。

輸出流與輸入流都是成對出現和使用。

輸出流資料包格式

輸出流資料包的内容說明如下:

◦Header 頭

◦Messages 消息體

◦HttpMessage(可選)

Header:頭資料包說明

0x4a 0x52 0x4d 0x49 Version Protocol

Header 包含四個固定位元組的辨別加版本号,協定資訊構成

Version 資料包說明(兩個位元組)

0x00 0x01

Protocol 協定(一個位元組),一共分三種 StreamProtocol、SingleOpProtocol 和 MultiplexProtocol。

分别對應的值如下:

◦StreamProtocol:0x4b

◦SingleOpProtocol:0x4c

◦MultiplexProtocol:0x4d

Messages:資料包說明

針對 Message 的消息體,由與上面的 Protocal 協定類型指定相關。

如果是 SingleOpProtocol 則消息體隻包含一條消息。一般用于 HTTP 方式請求。

The Messages are wrapped within a particular protocol as specified by Protocol. For the SingleOpProtocol, there may only be one Message after the Header, and there is no additional data that the Message is wrapped in. The SingleOpProtocol is used for invocation embedded in HTTP requests, where interaction beyond a single request and response is not possible.

SingleOpProtocol 和 MultiplexProtocol 消息則需要伺服器傳回 0x4e 位元組作為響應。

Message 的類型包含以下三種:

1.Call 表示 RMI 的調用操作

2.Ping 是檢測服務是否運作正常

3.DgcAck 當用戶端收到服務端的對象消息後告訴伺服器可以把傳回值對象進行 gc 操作。

Call 消息資料内容:

0x50 CallData

Ping 消息資料内容:

0x52

DgcAck 消息資料内容:

0x54 UniqueIdentifier

CallData:RMI 方法請求資料包

ObjectIdentifier Operation Hash Arguments(可選)

◦ObjectIdentifier (the target of the call)

◦Operation (a number representing the method to be invoked)

◦Hash (a number that verifies that client stub and remote object skeleton use the same stub protocol)

◦Arguments(a list of zero or more Arguments for the call)

UniqueIdentifier 資料包内容(一個位元組)

Number Time Count

Arguments:Values 對象

Object

HttpMessage:資料包說明

HttpPostHeader Header Message

HttpPosteHeader 是 HTTP 标準的請求 Header

Header 頭和 Message 資料包與上相同。

輸入流資料包格式

輸入流資料包的内容有以下三個方式:

ReturnData is the result of a "normal" RMI call

An HttpReturn is a return result from an invocation embedded in the HTTP protocol

A PingAck is the acknowledgment for a Ping message

ReturnData 資料包:

0x4e Returns

Returns 資料包,包含 ReturnData 和 PingAck。

ReturnData 資料包:

0x51 ReturnValue

PingAck 資料包:

0x53

ProtocolNotSupported 資料包:

0x4f

ReturnValue:返值資料包結構

0x01 UniqueIdentifier 傳回值對象(可選)

0x02 UniqueIdentifierException 對象

Note - ObjectIdentifier, UniqueIdentifier, and EndpointIdentifier are not written out using default serialization, but each uses its own special write method (this is not the writeObject method used by object serialization); the write method for each type of identifier adds its component data consecutively to the output stream.

在使用 RMI 釋出服務時,會使用到兩個端口。

一個是 RegisterPort,這個是 RMI 的服務注冊端口,通過以下 API 來指定。而且服務注冊端口必須要指定,預設使用 1099 端口。

Registry reg = LocateRegistry.getRegistry(registryPort);

注冊端口是用戶端服務連接配接的端口。

一個是 ServicePort,這個是 RMI 的服務的資料傳輸端口。該端口是真正在 RMI 用戶端與服務端進行資料通信互動的端口。是由注冊端口發現有用戶端連接配接後,進行後續配置設定的端口。預設值為 0 表示使用匿名随機端口。

API 的指定方式如下:

UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort);

[/quote]

RMI