codebase 也為非空,則將使用 ObjectOutputStream.wr
iteObject 方法將該 codebase 寫入流中;否則將使用 writeObject 方法將空值
寫入流中。注意:最好不要注解“java”包中的類,因?yàn)樗鼈儗?duì)于接收者來(lái)說(shuō)總
是可用的。
類注解是在序列化恢復(fù)期間用 ObjectInputStream.resolveClass 方法解析的。
resolveClass 方法首先用 ObjectInputStream.readObject 方法讀取注解。如果
注解(codebase URL)非空,它就獲得該 URL 的類加載器并試圖加載該類。利用
java.net.URLConnection 獲取類字節(jié),即可對(duì)該類進(jìn)行加載(與 web 瀏覽器的
applet 類加載器所用的機(jī)制相同)。
10.4 RMI 對(duì) HTTP POST 協(xié)議的使用
為了通過(guò)防火墻調(diào)用遠(yuǎn)程方法,有些 RMI 調(diào)用使用了 HTTP 協(xié)議,尤其是 HTTP
POST。在傳遞標(biāo)題中指定的 URL 可以為下列內(nèi)容之一:
http://<host>:<port>/ http://<host>:80/cgi-bin/java-rmi?forward=<port>
第一個(gè) URL 用于與特定 host 和 port 上的 RMI 服務(wù)器直接通信。第二種形式
的 URL 用于調(diào)用服務(wù)器上的“cgi”腳本,后者將把調(diào)用轉(zhuǎn)發(fā)給指定 port 上的
服務(wù)器。
HttpPostHeader 是 POST 請(qǐng)求的標(biāo)準(zhǔn) HTTP 標(biāo)題。HttpResponseHeader 是對(duì)傳
遞過(guò)程的標(biāo)準(zhǔn) HTTP 響應(yīng)。如果響應(yīng)狀態(tài)代碼不是 200,則認(rèn)為沒(méi)有返回值。注
意一個(gè) HTTP POST 請(qǐng)求中只能嵌入一個(gè) RMI 調(diào)用。
HttpMessage: HttpPostHeader Header Message
HttpReturn: HttpResponseHeader Return
----------------------------------------------------------------------
----------
注意 - 只有 SingleOpProtocol 出現(xiàn)在 HttpMessage 的標(biāo)題中。HttpReturn 不
包含用于確認(rèn)協(xié)議的字節(jié)。
----------------------------------------------------------------------
----------
10.5 RMI 的與應(yīng)用程序有關(guān)的值
本表列表出 RMI 所用的代表與應(yīng)用程序有關(guān)的值的非終結(jié)符號(hào)。該表將每個(gè)符號(hào)
映射為相應(yīng)的類型。每個(gè)符號(hào)都分別使用它所嵌入在其中的協(xié)議進(jìn)行格式化。
Count short
Exception java.lang.Exception
Hash long
Hostname UTF
Number int
Object java.lang.Object
ObjectNumber long
Operation int
PortNumber int
Primitive byte, int, short, long...
Time long
10.6 RMI 的多路復(fù)用協(xié)議
多路復(fù)用的目的是提供一種模型,其中兩個(gè)端點(diǎn)都可打開(kāi)多個(gè)到另一端點(diǎn)的全雙
工連接,而在相同環(huán)境下,使用其他工具(例如 TCP 連接)時(shí),只有一個(gè)端點(diǎn)能
打開(kāi)這樣的雙向連接。利用這種簡(jiǎn)單的多路復(fù)用協(xié)議,RMI 即可允許客戶在某些
其他協(xié)議無(wú)能為力的情況下,連接到 RMI 的服務(wù)器對(duì)象上。例如,有些 applet
環(huán)境的安全管理器不允許創(chuàng)建服務(wù)器套接字監(jiān)聽(tīng)到來(lái)的連接,以防止這種 appl
et 從直接套接字連接上導(dǎo)出 RMI 對(duì)象及提供遠(yuǎn)程調(diào)用服務(wù)。但是,如果該 app
let 可以打開(kāi)到其 codebase 主機(jī)的正常套接字連接,它就可以在該連接上使用
多路復(fù)用協(xié)議,從而允許 codebase 主機(jī)調(diào)用該 applet 所導(dǎo)出的 RMI 對(duì)象的方
法。本節(jié)介紹了多路復(fù)用協(xié)議的格式和規(guī)則。
10.6.1 定義
本節(jié)定義一些將在協(xié)議其余部分使用的術(shù)語(yǔ)。
端點(diǎn)是用多路復(fù)用協(xié)議連接的兩個(gè)用戶之一。
多路復(fù)用協(xié)議必須位于已有的雙向可靠字節(jié)流之上,假設(shè)由一個(gè)端點(diǎn)向另一個(gè)端
點(diǎn)進(jìn)行初始化。在當(dāng)前的 RMI 用法中,它通常是 TCP 連接,由 java.net.Sock
et 對(duì)象建立。該連接稱為具體連接。
多路復(fù)用協(xié)議有助于虛擬連接的使用。虛擬連接本身就是雙向的可靠字節(jié)流,代
表兩個(gè)端點(diǎn)之間的特定會(huì)話。一個(gè)連接上兩個(gè)端點(diǎn)之間的虛擬連接集組成一個(gè)多
路復(fù)用連接。使用多路復(fù)用協(xié)議,虛擬連接可以由任一端點(diǎn)打開(kāi)和關(guān)閉。虛擬連
接相對(duì)給定端點(diǎn)的狀態(tài)由在具體連接上發(fā)送和接收的多路復(fù)用協(xié)議元素定義。該
狀態(tài)涉及連接是打開(kāi)還是關(guān)閉、傳送的實(shí)際數(shù)據(jù)及相關(guān)的流控制機(jī)制。如果沒(méi)有
特別說(shuō)明,本節(jié)中其余部分將使用術(shù)語(yǔ)連接表示虛擬連接。
給定多路復(fù)用連接內(nèi)的虛擬連接由一個(gè) 16 位整數(shù)標(biāo)識(shí),稱為連接標(biāo)識(shí)符。因而
,一個(gè)多路復(fù)用連接中可能存在 65,536 個(gè)虛擬連接。實(shí)現(xiàn)可能會(huì)限制能同時(shí)使
用的虛擬連接數(shù)。
10.6.2 連接狀態(tài)和流控制
連接由用多路復(fù)用協(xié)議定義的各種操作來(lái)控制。下面是協(xié)議所定義的操作名:OP
EN、CLOSE、CLOSEACK、REQUEST 和 TRANSMIT。所有操作的準(zhǔn)確格式和規(guī)則將在
第 10.6.3 節(jié) “協(xié)議格式”中詳細(xì)介紹。
OPEN、CLOSE 和 CLOSEACK 操作控制連接的打開(kāi)和關(guān)閉,而 REQUEST 和 TRANSM
IT 操作用于在流控制機(jī)制的限制內(nèi)在打開(kāi)的連接上傳輸數(shù)據(jù)。
連接狀態(tài)
如果端點(diǎn)發(fā)送連接的 OPEN 操作或接收到連接的 OPEN 操作(且隨后沒(méi)有關(guān)閉它
),則該虛擬連接相對(duì)于該端點(diǎn)即為打開(kāi)的。下面介紹不同的協(xié)議操作。
如果端點(diǎn)發(fā)送連接的 CLOSE 操作,但隨后沒(méi)有接收到該連接的 CLOSE 或 CLOSE
ACK 操作,則該虛擬連接相對(duì)于該端點(diǎn)是等待關(guān)閉的。
如果端點(diǎn)從來(lái)沒(méi)有打開(kāi)過(guò)連接或接收到連接的 CLOSE 或 CLOSEACK 操作(且隨后
沒(méi)有打開(kāi)),則該虛擬連接相對(duì)于該端點(diǎn)是關(guān)閉的。
流控制
多路復(fù)用協(xié)議使用簡(jiǎn)單的包流控制機(jī)制允許多個(gè)虛擬連接并存于同一具體連接上
。流控制機(jī)制的高級(jí)要求是所有虛擬連接的狀態(tài)都是獨(dú)立的;一個(gè)連接的狀態(tài)不
會(huì)影響其他連接。例如,如果處理來(lái)自某個(gè)連接的數(shù)據(jù)的數(shù)據(jù)緩沖區(qū)已滿,應(yīng)不
會(huì)防礙其他連接的數(shù)據(jù)傳輸和處理。如果連接的繼續(xù)依賴于另一個(gè)連接的結(jié)束(
例如遞歸 RMI 調(diào)用時(shí)),則這一點(diǎn)將至關(guān)重要。因而,它的實(shí)際意義是實(shí)現(xiàn)必須
總能消耗和處理在具體連接上(假定它遵循該規(guī)范)準(zhǔn)備輸入的所有多路復(fù)用協(xié)
議數(shù)據(jù)。
每個(gè)端點(diǎn)具有兩個(gè)與各連接相關(guān)聯(lián)的狀態(tài)值:該端點(diǎn)已經(jīng)請(qǐng)求但尚未接收到的數(shù)
據(jù)字節(jié)數(shù)(輸入請(qǐng)求數(shù))和另一端點(diǎn)請(qǐng)求但該端點(diǎn)尚未提供的數(shù)據(jù)字節(jié)數(shù)(輸出
請(qǐng)求數(shù))。
端點(diǎn)的輸出請(qǐng)求數(shù)在從其他端點(diǎn)接收到 REQUEST 操作時(shí)將增大,而在它發(fā)送 TR
ANSMIT 操作時(shí)將減小。端點(diǎn)的輸入請(qǐng)求數(shù)在它發(fā)送 REQUEST 操作時(shí)將增大,而
在它接收到 TRANSMIT 操作時(shí)將減小。這些值如果為負(fù)就將違反協(xié)議。
如果端點(diǎn)發(fā)送 REQUEST 操作而導(dǎo)致其輸入請(qǐng)求數(shù)增大并超過(guò)其當(dāng)前可以無(wú)阻塞處
理的字節(jié)數(shù),則違反協(xié)議。但如果連接的用戶在等待讀取數(shù)據(jù),則應(yīng)確保其輸入
請(qǐng)求數(shù)大于零。
如果端點(diǎn)發(fā)送的 TRANSMIT 操作包含有比其輸出請(qǐng)求數(shù)更多的字節(jié),則違反協(xié)議
。它可以緩沖外流的數(shù)據(jù),直到連接用戶請(qǐng)求顯式刷新寫入到連接中的數(shù)據(jù)。但
如果因?yàn)轱@式的刷新或?qū)崿F(xiàn)的輸入緩沖區(qū)滿而必須在連接上發(fā)送數(shù)據(jù),則連接用
戶可能被阻塞,直到有足夠 TRANSMIT 操作。
在滿足上述規(guī)則的前提下,實(shí)現(xiàn)可以相對(duì)自由地發(fā)送 REQUEST 和 TRANSMIT 操作
。例如,如果其輸入緩沖區(qū)不空,則端點(diǎn)可以請(qǐng)求連接的更多數(shù)據(jù)。
10.6.3 協(xié)議格式
多路復(fù)用協(xié)議的字節(jié)流格式由連續(xù)的可變長(zhǎng)度記錄序列組成。記錄的第一個(gè)字節(jié)
是一個(gè)操作碼,它可以識(shí)別記錄的操作并可確定其內(nèi)容其余部分的格式。我們定
義了下列合法的操作碼:
值 名稱
0xE1 OPEN
0xE2 CLOSE
0xE3 CLOSEACK
0xE4 REQUEST
0xE5 TRANSMIT
如果記錄的第一個(gè)字節(jié)不是所定義的操作碼,則違反協(xié)議。下面各節(jié)介紹了每種
操作碼的記錄格式。
OPEN 操作
下面是 OPEN 操作的記錄格式:
大小(字節(jié)) 名字 描述
1 opcode 操作碼 (OPEN)
2 ID 連接標(biāo)識(shí)符
端點(diǎn)將發(fā)送 OPEN 操作以打開(kāi)指定的連接。如果ID 指向?qū)Πl(fā)送端點(diǎn)當(dāng)前已打開(kāi)或
即將關(guān)閉的連接,則違反協(xié)議。打開(kāi)連接后,連接的輸入和請(qǐng)求數(shù)狀態(tài)在兩個(gè)端
點(diǎn)上都為零。
接收到 OPEN 操作表示另一端點(diǎn)正在打開(kāi)指定的連接。打開(kāi)連接后,連接的輸出
和請(qǐng)求數(shù)狀態(tài)在兩個(gè)端點(diǎn)處都為零。
為防止兩端點(diǎn)間的標(biāo)識(shí)符沖突,有效連接標(biāo)識(shí)符空間將根據(jù)最高位的值分為兩半
。每個(gè)端點(diǎn)僅允許打開(kāi)高位為某一特定值的連接。啟動(dòng)具體連接的端點(diǎn)必須只打
開(kāi)高位為標(biāo)識(shí)符中的連接,另一端點(diǎn)必須只打開(kāi)高位為零的連接。例如,如果不
能創(chuàng)建服務(wù)器套接字的 RMI applet 啟動(dòng)了與其 codebase 主機(jī)的多路復(fù)用連接
,則該 applet 可以打開(kāi)標(biāo)識(shí)符范圍為 0x8000-7FFF 的虛擬連接,而服務(wù)器可以
打開(kāi)標(biāo)識(shí)符范圍為 0-0x7FFF 的虛擬連接。
CLOSE 操作
以下是 CLOSE 操作的記錄格式:
大小(字節(jié)) 名字 描述
1 opcode 操作代碼 (OPEN)
2 ID 連接標(biāo)識(shí)符
端點(diǎn)發(fā)送 CLOSE 操作以關(guān)閉指定的連接。如果 ID 指向?qū)Πl(fā)送端點(diǎn)當(dāng)前已關(guān)閉或
即將關(guān)閉的連接(如果它已發(fā)送過(guò)此連接的 CLOSE 操作,也可能是對(duì)接收端點(diǎn)即
將關(guān)閉的連接),則違反協(xié)議。 發(fā)送 CLOSE 后,連接就成為對(duì)發(fā)送端點(diǎn)即將關(guān)
閉的連接。因此,該端點(diǎn)將不能重新打開(kāi)該連接,直到它從另一端點(diǎn)接收到 CLO
SE 或 CLOSEACK 為止。
接收到 CLOSE 操作表示另一端點(diǎn)已關(guān)閉指定的連接,因此該連接已在接收端點(diǎn)上
被關(guān)閉。雖然接收端點(diǎn)可能不再為此連接發(fā)送其它操作(直到被再次打開(kāi)),但
它仍應(yīng)為此連接的讀者提供實(shí)現(xiàn)的輸入緩沖區(qū)中的數(shù)據(jù)。如果連接已經(jīng)被打開(kāi)(
而不是即將關(guān)閉),則接收端點(diǎn)必須用 CLOSEACK 操作作為響應(yīng)。
CLOSEACK 操作
以下是 CLOSEACK 操作的記錄格式:
大小(字節(jié)) 名字 描述
1 opcode 操作代碼 (OPEN)
2 ID 連接標(biāo)識(shí)符
端點(diǎn)發(fā)送 CLOSEACK 操作以表明已收到來(lái)自接收端點(diǎn)的 CLOSE 操作。如果收到操
作時(shí) ID 指向的連接不是對(duì)接收端點(diǎn)將要關(guān)閉的連接,則違反協(xié)議。
接收到 CLOSEACK 操作可將指定連接的狀態(tài)從即將關(guān)閉改為已關(guān)閉,因此以后還
可重新打開(kāi)連接。
REQUEST 操作
以下是 REQUEST 操作的記錄格式:
大小(字節(jié)) 名字 描述
1 opcode 操作代碼 (OPEN)
2 ID 連接標(biāo)識(shí)符
4 count 請(qǐng)求的額外字節(jié)數(shù)
端點(diǎn)發(fā)送 REQUEST 操作以增大指定連接的輸入請(qǐng)求數(shù)。如果 ID 未指向發(fā)送端點(diǎn)
打開(kāi)的連接,則違反協(xié)議。端點(diǎn)的輸入請(qǐng)求數(shù)按值 count 遞增。count 的值是
32 位有符號(hào)整數(shù)。如果為負(fù)數(shù)或零,則違反協(xié)議。
接收到 REQUEST 操作將使指定連接的輸出請(qǐng)求數(shù)按 count 增加。如果接收端點(diǎn)
即將關(guān)閉連接,則將忽略 REQUEST 操作。
TRANSMIT 操作
以下是 TRANSMIT 操作的記錄格式。
大小(字節(jié)) 名字 描述
1 opcode 操作碼 (OPEN)
2 ID 連接標(biāo)識(shí)符
4 count 傳輸?shù)淖止?jié)數(shù)
count data 傳輸數(shù)據(jù)
端點(diǎn)發(fā)送 TRANSMIT 操作后,才真正在指定連接上傳輸數(shù)據(jù)。如果 ID 未指向?qū)?nbsp;
發(fā)送端點(diǎn)打開(kāi)的連接,則違反協(xié)議。端點(diǎn)的輸出請(qǐng)求按值 count 遞減。count 的
值是 32 位有符號(hào)整數(shù)。如果為負(fù)數(shù)或零,則違反協(xié)議。如果 TRANSMIT 操作導(dǎo)
致輸出請(qǐng)求數(shù)成為負(fù)數(shù),則也違反協(xié)議。
接收到 TRANSMIT 操作時(shí)從連接中可讀到的字節(jié)隊(duì)列將增加 count 字節(jié)的數(shù)據(jù)。
接收端點(diǎn)的輸入請(qǐng)求數(shù)按值 count 遞減。如果這會(huì)使輸入請(qǐng)求數(shù)成為零,而該連
接的用戶卻試圖讀取更多數(shù)據(jù),則該端點(diǎn)應(yīng)用另一個(gè) REQUEST 操作作為響應(yīng)。如
果接收端點(diǎn)即將關(guān)閉連接,則將忽略 TRANSMIT 操作。
違反協(xié)議
如果出現(xiàn)上述違反協(xié)議的現(xiàn)象,或者在具體連接中檢測(cè)到通訊錯(cuò)誤,則多路復(fù)用
連接即被關(guān)閉。實(shí)際連接將被終止,而所有虛擬連接也被立即關(guān)閉。連接的用戶
可以讀取虛擬連接中已經(jīng)可以讀取的數(shù)據(jù)。
凡是有該標(biāo)志的文章,都是該blog博主Caoer(草兒)原創(chuàng),凡是索引、收藏
、轉(zhuǎn)載請(qǐng)注明來(lái)處和原文作者。非常感謝。