網絡I/O:Socket→RMI
★Socket
Socket編程可能大家都很熟,所以就不多討論了,只是說通過socket把數據保存到遠端服務器或從網絡socket讀取數據也不失為一種值得考慮的方式。
★RMI
RMI機制其實就是RPC(遠程過程調用)的Java版本,它使用socket作為基本傳輸手段,同時也是序列化最重要的一個應用。現在網絡傳輸從編程的角度來看基本上都是以流的方式操作,socket就是一個例子,將對象轉換成字節流的一個重要目標就是為了方便網絡傳輸。
想象一下傳統的單機環境下的程序設計,對於Java語言的函數(方法)調用(註意與C語言函數調用的區別)的參數傳遞,會有兩種情況:如果是基本數據類型,這種情況下和C語言是一樣的,采用值傳遞方式;如果是對象,則傳遞的是對象的引用,包括返回值也是引用,而不是一個完整的對象拷貝!試想一下在不同的虛擬機之間進行方法調用,即使是兩個完全同名同類型的對象他們也很可能是不同的引用!此外對於方法調用過程,由於被調用過程的壓棧,內存“現場”完全被被調用者占有,當被調用方法返回時,才將調用者的地址寫回到程序計數器(PC),恢復調用者的狀態,如果是兩個虛擬機,根本不可能用簡單壓棧的方式來保存調用者的狀態。因為種種原因,我們才需要建立RMI通信實體之間的“代理”對象,譬如“存根”就相當於遠程服務器對象在客戶機上的代理,stub就是這麽來的,當然這是後話了。
本地對象與遠程對象(未必是物理位置上的不同機器,只要不是在同一個虛擬機內皆為“遠程”)之間傳遞參數和返回值,可能有這麽幾種情形:
值傳遞:這又包括兩種子情形:如果是基本數據類型,那麽都是“可序列化”的,統統序列化成可傳輸的字節流;如果是對象,而且不是“遠程對象”(所謂“遠程對象”是實現了java.rmi.Remote接口的對象),本來對象傳遞的應該是引用,但由於上述原因,引用是不足以證明對象身份的,所以傳遞的仍然是一個序列化的拷貝(當然這個對象也必須滿足上述“可序列化”的條件)。
引用傳遞:可以引用傳遞的只能是“遠程對象”。這裏所謂的“引用”不要理解成了真的只是一個符號,它其實是一個留在(客戶機)本地stub中的,和遠端服務器上那個真實的對象張得一模一樣的鏡像而已!只是因為它有點“特權”(不需要經過序列化),在本地內存裏已經有了一個實例,真正引用的其實是這個“孿生子”。
由此可見,序列化在RMI當中占有多麽重要的地位。
網絡I/O:Socket→RMI