1. 程式人生 > >java原始碼剖析之socket(一)

java原始碼剖析之socket(一)

    不知不覺又到了新的的一週,時間在悄悄的溜走,所辛的是自己也在緩慢的推進著自己的學習計劃。 

    這周按照計劃檢視的是socket系列的相關類,儘管這之前就已經看過一遍,不過當時是越看越蒙,完全找不到北。 隨著自己能力的提升,回過頭來又去看一遍,還是看不懂其中的精髓,不過至少比起第一遍已經要好了很多很多。 

    按照慣例,先上圖:

    

    從圖中可以看出socket系列的類好像沒有io流體系的類複雜。   但是實際上socket裡面涉及的內容理解起來還是要難一些的。  接下來按照時間線進行一個學習的記述:

    首當其衝的是Socket,套接字:

     套接字為一個普通的java類,但是它的邏輯實現卻主要依賴了一個以SocketImpl抽象類為基類的系列類,並且它的相關邏輯是預設託管給一個SocksSocketImpl(SocketImpl的後代類)的,同時SocksSocketImpl又將主要的邏輯託管給父類,最終由其兄弟類DualStackSocketImpl或者是TwoStackSocketImpl實現核心的業務程式碼,事實上是呼叫了native方法。                           

    Socket提供給了外部兩種例項化方式,分別為面向連線的Socket例項,面向非連線的Socket例項。 其核心在於是否呼叫了本地的connect()方法。 

       

    

    下面是面向連線的:

        

    

    注意這個面向連線的Socket的實際構造方法為私有的,並不能被我們直接呼叫。 

    還有幾個面向連線的構造方法,但都大同小異就不上圖了。   總之吧,能夠唯一確定一個終端,也就是ip地址和埠確定,那麼都應該是面向連線的,除此之外應該是面向無連線的,不然不就報錯了嘛哈哈,設計者早將我們可能遇到的問題給考慮進了,作為一個成熟的產品。 有一個例外就是,有個構造是隻提供埠,但是也是也是面向連線的,它會將主機預設為本機localhost。   還有一種記的方法就是,面向非連線的socket只有三個,第一個是空參,第二個是代理,第三個是SocketImpl。 其餘的就都是面向連線的。

    這裡臨時想到一個問題,那就是如果我們呼叫了SocketImpl的構造,那麼我們實際上是為這個Socket準備了什麼條件呢?  實際上通過看它們的繼承和依賴關係圖可以知道,SocketImpl系列的有很多,其中一級抽象的有:AbstractPlainSocketImpl,二級實現類有:DualSocketImpl,TwoSocketImpl,PlainSocketImpl。(它們同時為兄弟關係,但是在邏輯上卻體現出父子關係,因為PlainSocketImpl實際上是在DualSocketImpl和TwoSocketImpl二者中選其一作為實際實現類,並且它們的選擇關係是通過系統的版本確定的,因為系統版本支援的具體的協議棧有區別好像。)。 三級實現類有:SocksSocketImpl。   我們要作為這個構造方法的實參,那麼傳抽象類的可能性不大。實際上就算傳抽象類,最終還是要走到實現類去。  因此考慮PlainSocketImpl和TwoSocketImpl。   那麼應該可以大致猜測出來,其為Socket提供的是底層協議棧操作的方式或者一些相關的操作規則。至於為什麼不能面向連線呢? 那就涉及到等會要介紹的依賴類了。

     在此之前補充一下Socket的另外幾個我認為較重要的方法或注意的地方吧:

        

    大體意思就是:通過toString方法可以看到這個socket的一些基本資訊,同時在j2se1.3以前,所有的socket都是面向連線的。 

    接下來介紹socket的另一個主要的依賴類:InetAddress。 其全稱應該為:InternetAddress,簡寫了還不太好識別出來。 

    依然先看圖,包括這個類的官方說明:

        

    

        

    可以知道,它是作為一個ip地址提供socket資源,檢視它的類宣告,發現它為一個基本類,但是我感覺它用的時候相當於充當了一個抽象類的功能。  同時看類的繼承依賴關係圖可以知道:其有兩個子類,Inet4Address和Inet6Address,分別對應ipv4地址和ipv6地址。  同時它的類靜態成員也明確的表明了這一點,並且是通過int作為一個標識,來識別是ipv4還是ipv6。  這個類本身的構成也是比較複雜的,各種內部類,同時它的內部類有一點奇葩,它將自己也弄成了一個內部類,這將造成一種什麼情況呢?那就是無限的遞迴,這也是我在除錯的時候發現的這樣的奇怪的問題,不知它是採用何種儲存結構或者指標怎麼指能夠實現這種功能。在此就上圖證明一下:

    

    

    這是在除錯的某一步,檢視其物件的組成。  事實上,這個impl物件可以一直開啟下去,這就奇怪了,難道這樣不是無限遞迴嗎?哎,燒腦。 跳過繼續介紹

    另一個比較重要的一點的內部類為:InetAddressHolder,好多類都有這種內部類,好像是一種設計模式,叫啥給搞忘了,以後有機會研究。 

        上圖說明問題:

        

    這是InetAddress對外開放的其中一個構造方法,同時它是靜態的,因此可以說是一個工具方法吧。 主要就是把主機名進行一些必要的標準化和將ip地址標準化,之後進行一個標準Inet4Address的構造或者Inet6Address的構造。 繼續看它的子類,這裡主要看一下ipv4:

    

    

    

    

    這幾個方法主要做了這些事情:判斷某個Ip地址是否為保留地址,如10.xxx.xxx.xxx,172.16.xxx.xxx,192,168.xxx.xxx,;將一個ip的byte資料通過移位操作,可以看到它是以位元組(八位)進行操作的,將每個位元組取出進行一個與運算,並以byte陣列的方式返回;將Ip地址轉化為我們平時看到的  xxx.xxx.xxx.xxx型別。 

       馬上上課了,那就下午接著寫。