Peer-to-Peer Sockets 工程入門

版權聲明:能夠任意轉載,轉載時請務必以超連接形式標明文章原始出處和做者信息及本聲明
做者:
Brad Neuberg ;gracepig
原文地址:
http://www.onjava.com/pub/a/onjava/2003/12/03/p2psockets.html
中文地址:
http://www.matrix.org.cn/resource/article/43/43854_Peer-to-Peer-Sockets.html
關鍵詞: Peer-to-Peer Sockets

Peer-to-Peer (P2P)Sockets工程在JXTA peer-to-peer虛擬網絡從新實現了對應於標準TCP/IP網絡中的Java標準的Socket,ServerSocket,和InetAddress等類。該工程同時還引入了一些注入Jetty web server,Apache XML-RPC客戶端和服務器庫,Apache Jasper JSP引擎之類的流行web package。使這些服務能夠運行在Peer-to-Peer Sockets 的框架下。

在這片文章結束的時候,你會理解對P2P Sockets packages的需求和以及開發它的動機,學會怎麼配置P2P Socket 庫使之在你的系統上可以運行,學會怎麼樣創建P2P的服務器和客戶端Socket,怎麼使用P2P的InetAddress 類,還包括框架下的安全問題以及它的侷限性。

動機

P2P Socket工程的設計的使用對象是對如下幾個領域有興趣的開發者:
●將Internet迴歸到end-to-end的原則當中
●一種繞過ICANN和Verisign的替代peer-to-peer域名系統,這個系統是徹底分佈式的,對更新擁有比標準DNS快的多的響應速度。
●一種任何人均可以創建活着使用網絡服務的Internet,及時他們使用動態的IP地址或是沒有IP地址,或是隻有內網地址(NAT),或者是在ISP的防火牆以後。
●一個每個Peer都可以自動的創建一個Web Server,提供XML-RPC服務,可以快速的將這種服務提供給其餘的Peer。
●使爲Peer-to-Peer網絡添加Java Socket和ServerSocket 的應用更加容易
●享受更酷的科技

P2P Socket 工程在JXTA peer-to-peer網絡上從新實現了標準java.net報當中的類。一些人可能要問「難道標準TCP/IP socket和ServerSocket不是已是peer-to-peer的了嗎?」標準的TCP/IP socket和server socket在理論上是peer-to-peer的,不過因爲防火牆,NAT設備,以及DNS所存在的政治或是技術的問題,在實際上卻沒有作到這一點。首先,Internet上的許多peer使用的都是經過DHCP協議取得的動態IP,這些IP由經過NAT設備共享和過濾,還有一些IP地址因爲防火牆的限制,很難被訪問到。在這樣的條件下創建server socket應用要麼是不可能的,要麼就須要在應用層進行精妙的控制來繞過這些限制。其次,TCP/IP Socket依賴於DNS系統來將用戶友好的主機名轉變爲IP地址。DNS在理論上就是辦分佈式的,可是在管理層面上,DNS是在ICANN下集中式管理的,而ICANN是一個反應遲鈍的,沒有創新意識的組織。再次,標準的DNS對對那些過濾或是使用動態IP地址的edge-peer支持的並很差,更新須要花費很長的時間傳播下去並且並不提供presence信息。對那些想要開發可以擴展DNS到新的領域(例如將即時消息的用戶名和存在信息加入到DNS)的新應用的開發者來講,DNS系統的技術和政治因素阻礙了他們的工做。

JXTA是一個用於在TCP/IP之上創建peer-to-peer覆蓋網絡的開源工程。在網絡中的沒一個peer都會被分配到一個和IP地址相似的號碼,即時他們沒有固定的IP地址或是出在防火牆以後。在JXTA 網絡上的super-peer通信運行應用層的路由協議來儲存例如若是到達其餘的peer,如何加入peer group,其餘peer提供了怎麼樣的內容之類的信息。JXTA應用層在Peer之間提供了中繼的代理服務,是出在防火牆或是NAT後的Peer能夠正常的通訊。Peer能夠本身組織成爲Peer Group,這樣能夠將全部的查詢請求限定在natural security container當中。任何peer均可以分佈式的創建併發佈一個peer group,其餘的Peer經過使用其餘的super-peer能夠搜索並發現這些peer group。Peer之間的通訊經過pipe的方式來進行,這和Unix系統當中的Pipe很是的相似。Pipe是對兩個peer之間通信方式的一種抽象,它幫助peer互相通信,即便他們處在不一樣的網絡區域當中。

JXTA是一種很是強大的框架。可是,它並非一種容易學習的框架,將現有的軟件移植到JXTA下也不是一件容易的事情。P2P Sockets成功地將JXTA隱藏起來,使之看起來就像是傳統的TCP/IP網絡。若是peer想要成爲服務器,他只須要簡單的使用包含他們想使用的domain name和端口的P2P Server Socket就能夠了。P2P的客戶端能夠經過host名和特定的端口號來創建Socket鏈接訪問那些服務。Host能夠被解析爲域名,例如www.nike.laborpolicy,或是IP地址,例如44.22.33.22。在這些場景以後,host實際被解析爲JXTA原語,而不是被解析爲DNS或是TCP/IP。舉例來講:域名www.nike.laborpolicy其實是JXTA peer group 的廣告消息中的一個NAME字段。P2P Sockets和Server socket 與正常的TCP/IP Socket和ServerSocket的使用方法徹底相同。咱們爲但願瞭解內幕和那些已經懂得JXTA的用戶提供了一張表(http://www.onjava.com/onjava/2003/12/03/examples/table.html),在這張表中能夠查詢到傳統TCP/IP概念上的域名,IP地址等概念和JXTA中對等概念的對應關係。

使用這種方式的好處是多方面的。首先,程序員能夠將他們在標準TCP/IP Socket和Server Socket的知識應用到JXTA peer-to-peer網絡當中而不須要專門學習JXTA。其次,全部的P2P Socket 的代碼都是標準java.net中類的子類,例如java.net.Socket,因此現存的網絡應用能夠很容易的移植到peer-to-peer網絡當中。 P2P Socket工程已經將不少現存的軟件移植到了peer-to-peer網絡當中,其中包括web服務器(Jetty),它能夠接收請求,被在peer-to-peer 網絡上提供內容服務;一個servlet和JSP引擎(Jetty 和 Jsper),它可使現存的servlet和JSP直接在P2P網絡中應用;一個XML-RPC客戶端和服務器(Apache XML-RPC),它能夠訪問和對外提供P2P XML-RPC 端點;一個HTTP/1.1客戶端(Apache Commons HTTP-Client),它能夠訪問P2P的web 服務器;一個網關(Smart Cache),它能夠是現有瀏覽器訪問P2P的P2P web 站點;和WikiWiki(JSPWiki),它可以在你的主機上創建Wiki站點,使其餘的Peer能夠經過P2P網絡訪問,並編輯。全部的這些軟件在移植以後都可以正常的使用而且和之前看起來徹底同樣。P2P Socket的抽象很是的成功,移植這些軟件所花費的時間僅僅是30分鐘到幾個小時不等。P2P Socket工程是徹底開源的,大部分都採用BSD-type證書,因爲是使用Java編寫的,因此也具備跨平臺的特性。

因爲P2P Socket是創建在JXTA之上的,因此它能夠很容易的處理一些傳統的ServerSocket和Socket所不能處理的狀況。第一,在P2P Socket上創建的ServerSocket,具備fail-over(不知道怎麼翻譯,應該是可靠性之類的意思)和易擴展的特性。若是不一樣的Peer能夠啓動ServerSocket使用同一個域名和端口,例如www.nike.laborpolicy 端口號:80。當一個客戶端打開P2P socket鏈接到www.nike.laborpolicy 端口號:80時,它會隨機的鏈接到一個提供一個使用這個域名和端口的主機上。全部的這些服務器Peer可能提供一樣的Web頁面,這就是能夠將用戶的請求分佈到不一樣的服務器之上同時也就使得某一個服務器的崩潰更容易被恢復。這一點和DNS round-robin很是的類似,在DNS round-robin當中一個域名能夠被解析爲多個IP地址用來進行負載均衡。第二,因爲P2P Socket並不使用DNS系統,主機名能夠任意指定。用戶能夠創建他本身的個性結尾,例如www.boobah.cat 或是www.cynthia.goddess,或是應用肯定的名字,例如一個即便消息系統使用Brad GNUberg或是Fidget666看成域名。第三,一個指定域名的服務端口能夠分佈在全世界不少的Peer當中。舉例來講,假設你有一個虛擬主機名www.nike.laborpolicy,一個Peer能夠在80端口提供web頁面,另外一個Peer可使用2000端口提供即時消息,最後一個Peer能夠在3000端口爲其餘Peer提供即時的RSS更新。如今一個域名能夠由不少分佈不一樣的Peer協同在一塊兒提供服務。

需求與配置
要開發和使用P2P Socket你必須下載和安裝一下的這些軟件。
JDK 1.4+
P2P Socket只能工做在JDK 1.4或是更新版本的Java虛擬機之上,因爲P2P Socket是Java.net.InetAddress的子類,在1.4以前,這個類是final類型的。

Ant 1.5.3+
用來構建和運行P2P Socket以及相似於Jetty 和 Jasper之類的擴展

P2PSockets-1.0-beta1.zip
P2P Socket 的最新發布包

安裝和配置好JDK和Ant,並保證它們均可以在命令行下正確運行。將P2PSockets-1.0-beta1.zip解開到硬盤上。在目錄名當中不能出現空格,不然P2P Sockets的構建文件不能正常工做。

必須將JAR文件p2psockets/lib/ant-contrib-0.5.jar加入到你的CLASSPATH當中去。在Windows當中可使用下面這個命令:

set CLASSPATH=%CLASSPATH%;c:\p2psockets\lib\ant-contrib-0.5.jar

P2P Sockets的目錄包含兩個不一樣的子目錄,test/clientpeer和test/serverpeer,它們中有已經設置好的JXTA配置信息(分別在test/clientpeer/.JXTA和test/serverpeer/.JXTA當中)。若是你想要了解更多的關於JXTA的配置問題,你能夠閱讀JXTA配置指南。兩個測試peer已經被配置爲最差的狀況下工做模式,也就是peer處在防火牆或是NAT設備以後,也就是說用戶必須使用其餘的中間Peer來中繼它們的請求。若是用戶不處在這種環境下,這種配置方式也是能夠工做的。使用JXTA的一個好處就是,當你在使用這個系統的時候,它對你的程序幾乎是透明的。

當你在測試本文中的代碼的時候,你必須鏈接到Internet。這樣作基於一下的兩個緣由:首先,例子程序使用Sun提供的公共JXTA服務器來將啓動peer引入JXTA網絡當中;其次,在一些操做系統上(例如Windows XP, 缺省),網絡系統在你沒有鏈接到網絡上時會自動關閉,這樣就會阻礙運行在同一個主機上的客戶端peer和服務器peer互相通信。

創建一個P2P Server Socket

創建一個P2P server Socket的方法和創建一個標準的java.net.ServerSocket徹底同樣。html

// start a server socket for the domain
// "www.nike.laborpolicy" on port 100
java.net.ServerSocket server = new java.net.P2PServerSocket("www.nike.laborpolicy", 100);



經過上面的這種方法,咱們能夠創建一個server socket在域名www.nike.laborpolicy 端口100上監聽客戶端請求。在這種狀況下,P2PServerSocket的代碼將會去搜索一個名字叫作www.nike.laborpolicy的peer group。一旦它找到了這個peer group,它會加入;接着它會建立併發佈一個JXTA peer group 的廣告消息在當中會有一個依照特定格式的Name域。這個域使用hostname/IP address,例如 www.nike.laborpolicy/44.33.67.22這種格式。咱們使用通配符來搜索基於JXTA rendezvous 服務器上的主機名或是IP地址,例如www.nike.laborpolicy/*來進行在不知道IP地址狀況下的搜索,或是採用*/44.33.67.22來進行指定IP地址的搜索。一旦咱們找到或是建立了這個peer group,咱們就能夠發佈這個JXTA pipe advertisement到這個peer group當中去,在這個廣告信息當中使用Name字段設置端口,例如80。

在創建了這個server socket之後,用戶能夠像使用普通的java.net.ServerSocket同樣的使用,等待一個客戶端的請求,並得到InputStream或是OutputStream來進行通信:java

java.net.Socket client = server.accept();
// now communicate with this client
java.io.DataInputStream in = new DataInputStream(client.getInputStream());
java.io.DataOutputStream out = new DataOutputStream(client.getOutputStream());
out.writeUTF("Hello client world!");
String results = in.readUTF();
System.out.println(results);



儘管客戶端看起來和正常的java.net.Socket很類似,但實際上它已是經過JXTA peer-to-peer網絡來進行通信了,請求與響應消息都是經過其餘的peer進行中繼來穿越NAT和網絡區域的。固然,這一些都是隱藏在後臺的。

與普通的server socket不一樣,咱們須要初始化並登陸進入咱們的peer-to-peer網絡。在咱們創建P2PServerSocket以前,咱們須要進行如下的操做:程序員

// sign into the peer-to-peer network, using
// the username "serverpeer", the password "serverpeerpassword",
// and create/find a scoped peer-to-peer network named "TestNetwork"
java.net.P2PNetwork.signin("serverpeer", "serverpeerpassword", "TestNetwork");



頭兩個參數是用來登陸進入peer-to-peer網絡的用戶名和密碼。這是在用戶設置JXTA Configurator的時候的時候輸入的,一個Swing的對話框(在第一運行JXTA 平臺的時候會彈出)會容許你在P2P 網絡上配置你的Peer。在你本身的應用當中,你能夠從命令行和GUI的方式獲取這些值。P2P Sockets 包裏面預先配置好了兩個JXTA Peer分別放在test/clientpeer和test/serverpeer下面。

最後的一個參數(上面例子中的TestNetwork)是你的peer-to-peer網絡的惟一名字。創建在P2P Sockets之上的不一樣peer-to-peer網絡能夠在不知道對方存在的狀況下共存。客戶端和服務器在特定的peer-to-peer網絡當中建立和解析它們的server sockets和sockets。最後的一個參數就是你私有的,由應用指定的peer-to-peer網絡。若是你建立了一個名叫TestNetwork的server socket而另外一個用戶登陸進入一個名叫InstantMessagingNetWork的serversocket,它們就不能找到對方並進行通信。

接下來咱們來看看P2PNetwork這個類是怎樣工做的。當你調用signin方法的時候,網絡字符串(例子中的TestNetwork)將會被哈希爲一個MD5的peer group ID;這樣就會保證在咱們以Peer ID搜索的時候,這個應用的名字是全局惟一的。全部的域名和IP地址解析都發生在這個應用的peer group內部。應當注意到在test/clientpeer和test/serverpeer當中使用的JXTA配置文件都將使用Sun rendezvous服務器做爲加入JXTA網絡的引導服務器;當你想要使用其餘的初始服務器時,你須要修改配置文件。

對於程序員來講,你能夠根據本身的應用或是所建立網絡的類型選擇本身的網絡名,例如:MyApplicationsNetwork 或是 AcmeCompanyInformationNetwork。

最終的代碼以下所示:web

import java.io.InputStream;
import java.io.OutputStream;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.P2PServerSocket;
import java.net.P2PNetwork;
public class ExampleServerSocket {
   public static void main(String args[]) {
      try {
         // sign into the peer-to-peer network,
         // using the username "serverpeer", the password "serverpeerpassword",
         // and create/find a scoped peer-to-peer network named "TestNetwork"
         System.out.println("Signing into the P2P network...");
         P2PNetwork.signin("serverpeer", "serverpeerpassword", "TestNetwork");
         // start a server socket for the domain
         // "www.nike.laborpolicy" on port 100
         System.out.println("Creating server socket for " + "www.nike.laborpolicy:100...");
         ServerSocket server = new P2PServerSocket("www.nike.laborpolicy", 100);
        
         // wait for a client
         System.out.println("Waiting for client...");
         Socket client = server.accept();
         System.out.println("Client Accepted.");
                
         // now communicate with this client
         DataInputStream in = new DataInputStream(client.getInputStream());
         DataOutputStream out = new DataOutputStream(client.getOutputStream());
         out.writeUTF("Hello client world!");
         String results = in.readUTF();
         System.out.println("Message from client: " + results);
                
         // shut everything down!
         client.close();
         server.close();
      }
      catch (Exception e) {
         e.printStackTrace();
         System.exit(1);
      }
   }
}




使用P2P Socket來鏈接P2P Server Socket

創建和使用P2P socket鏈接P2P Server socket同樣容易:
首先,須要登陸進去指定的peer-to-peer網絡當中:shell

// sign into the peer-to-peer network,
// using the username "clientpeer", the password "clientpeerpassword",
// and find the peer-to-peer network named "TestNetwork"
java.net.P2PNetwork.signin("clientpeer", "clientpeerpassword", "TestNetwork");



接下來,使用指定的主機名和端口號建立你想要鏈接的socket:apache

java.io.DataInputStream in = new DataInputStream(socket.getInputStream());
java.io.DataOutputStream out = new DataOutputStream(socket.getOutputStream());
String results = in.readUTF();
System.out.println(results);
out.writeUTF("Hello server world!");





下面是完整的代碼:瀏覽器

import java.io.InputStream;
import java.io.OutputStream;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.net.Socket;
import java.net.P2PSocket;
import java.net.P2PNetwork;

public class ExampleClientSocket {
   public static void main(String args[]) {
      try {
         // sign into the peer-to-peer network,
         // using the username "clientpeer", the password "clientpeerpassword",
         // and find a network named "TestNetwork"
         System.out.println("Signing into the P2P network..");
         P2PNetwork.signin("clientpeer", "clientpeerpassword", "TestNetwork");
                
         // create a socket to connect to the
         // domain "www.nike.laborpolicy" on port 100
         System.out.println("Connecting to server socket! at " + "www.nike.laborpolicy:100...");
         Socket socket = new P2PSocket("www.nike.laborpolicy", 100);
                 System.out.println("Connected.");
                
         // now communicate with this server
         DataInputStream in = new DataInputStream(socket.getInputStream());
         DataOutputStream out = new DataOutputStream(socket.getOutputStream());
         String results = in.readUTF();
         System.out.println("Message from server: " + results);
         out.writeUTF("Hello server world!");
                
         // shut everything down
         socket.close();
      }
          
      catch (Exception e) {
         e.printStackTrace();
         System.exit(1);
      }
   }
}




運行P2P Server Socket和Socket的例子

打開兩個不一樣的Shell 窗口。在兩個窗口當中,鍵入下面的命令來設置使用Ant構建所需的環境變量(修改環境變量使之指向你安裝P2P sockets和JDK的位置):

set p2psockets_home=c:\p2psockets
set JAVA_HOME=c:\j2sdk1.4.1


在兩個窗口中,都進入p2psockets的目錄,例子源碼在p2psockets/src/examples目錄下面,名字分別叫作ExampleClientSocket.java和ExampleServerSocket.java。全部的代碼都已經編譯進入p2psockets/dist/examples目錄當中去,可是若是你想要從新編譯它們的時候,在其中一個shell當中使用下面的這個命令:

ant clobber build jar

要運行客戶端和服務器,在一個窗口當中鍵入下面的命令來啓動例子P2P server socket:

ant example-serversocket-run

你會看到以下的屏幕顯示:

Buildfile: build.xml
example-serversocket-run:
Signing into the P2P network...
Using the application peer group name TestNetwork
Waiting for RendezVous Connection.........
Finished connecting to RendezVous.
Creating server socket for
www.nike.laborpolicy:100...
Waiting for client...


在另外一個窗口當中,輸入以下的命令啓動p2p client socket:

ant example-clientsocket-run

你會在client peer 的窗口當中看到以下的輸出:

Buildfile: build.xml
example-clientsocket-run:
Signing into the P2P network..
Using the application peer group name TestNetwork
Waiting for RendezVous Connection......
Finished connecting to RendezVous.
Connecting to server socket at
www.nike.laborpolicy:100...
Connected.
Message from server: Hello client world!



在服務器窗口,你會看到以下的輸出:

Buildfile: build.xml
example-serversocket-run:
Signing into the P2P network...
Using the application peer group name TestNetwork
Waiting for RendezVous Connection.........
Finished connecting to RendezVous.
Creating server socket for
www.nike.laborpolicy:100...
Waiting for client...
Client Accepted.
Message from client: Hello server world!



祝賀你,你已經創建了一個簡單的peer-to-peer網絡,這並無須要你作太多的工做,也沒有須要你在基本的Java sockets和server sockets之外的知識。

若是你遇到困難,首先確保你已經鏈接到互聯網上,是否使用Java 1.4+,確保P2P Socket package 所安裝的目錄名當中沒有空格。也許你根據你所使用的特殊網絡環境調整你的JXTA網絡設置。若是你想要在兩個被NAT所阻塞的不一樣的機器上運行客戶端和服務器Socket例子,也許你是碰到了P2P Sockets所公開的一個bug。

檢查一個主機名,IP地址,或是端口號是否被佔用
缺省狀況下,P2PInetAddress和P2PServerSocket類並不會去檢查主機名,IP地址,或是端口號是否被佔用。這樣作的緣由是應用的開發者可使用獨一無二的方法來使用P2P Server Socket而傳統的Socket是不能這樣作的。舉例來講,不一樣的peer能夠啓動P2P Server sockets使用同一個主機名和端口,經過這種方式來提供容錯性和擴展性。若是咱們想要在發現地址已經被佔用的時候拋出一個異常的話,這種可能行就被排除了。

儘管如此,系統提供了用於發現主機名,IP地址或是端口號是否被佔用的方法。這些是java.net.P2PNameService當中的靜態方法。例子以下:安全

boolean nameAvailable = P2PNameService.isHostNameTaken("www.nike.laborpolicy");
boolean portAvailable = P2PNameService.isPortTaken("www.nike.laborpolicy", 80);
boolean addressAvailable = P2PNameService.isIPAddressTaken("33.44.74.12");



在你須要爲你的server建立一個惟一的實例的時候能夠在建立P2P Server socket以前調用這些方法。(請閱讀侷限性和安全問題一章,在P2P的域名欺騙)

你已經瞭解到很多關於P2P Socket和server Socket的東西。接下來的這一章將會介紹若是使用P2P Sockets包所提供的其餘與標準TCP/IP兼容的類的技術細節。你並非必定須要瞭解這些內容,但若是你瞭解,你可使用這些InetAddress類,本地環回地址(127.0.0.1)或是任播地址(0.0.0.0)。若是你跨過下面的章節,請確保你閱讀了文章末尾處侷限性和安全問題那一章。

使用P2P InetAddress 類

P2P Sockets 包中包含了對於java.net.InetAddress的一個子類實現。

下面的例子介紹了幾種不一樣的方法,用來建立一個P2PInetAddress對象。服務器

// Create an InetAddress where we know the host
// name but not the IP address.
// This will not search the network to find the
// corresponding IP address.
InetAddress inetAddr = P2PInetAddress.getByAddress("www.nike.laborpolicy", null);

// Create an InetAddress where we know the IP
// address but not the host name.
// This will not search the network to find the
// corresponding host name.
InetAddress inetAddr = P2PInetAddress.getByAddress("55.32.77.34", null);

// Create an InetAddress where we know both the
// IP address and the host name.
// No searching will occur on the network
byte ipAddress[] = new byte[4];
ipAddress[0] = 55;
ipAddress[1] = 32;
ipAddress[2] = 77;
ipAddress[3] = 34;
InetAddress inetAddr = P2PInetAddress.getByAddress("www.nike.laborpolicy", ipAddress);

// Create an InetAddress object using the hostname.
// The network will be searched for the corresponding IP address
InetAddress inetAddr = P2PInetAddress.getByName("www.boobah.cat");

// Create an InetAddress object using the hostname.  
// The network will be searched for the corresponding IP address
InetAddress inetAddress[] = P2PInetAddress.getAllByName("www.boobah.cat");

// Create an InetAddress object using the IP address.  
// The network will be searched for the corresponding host name
byte ipAddress[] = new byte[4];
ipAddress[0] = 55;
ipAddress[1] = 32;
ipAddress[2] = 77;
ipAddress[3] = 34;
InetAddress inetAddr = P2PInetAddress.getByAddress(ipAddress);

// Get the host name and IP address for the local host
InetAddress inetAddr = P2PInetAddress.getLocalHost();



一旦你建立了一個一個P2PInetAddress對象,你就能夠像使用一個正常的InetAddress對象那樣使用它:網絡

InetAddress inetAddr = P2PInetAddress.getByName("www.boobah.cat");
String hostName = inetAddr.getHostName();
String ipAddressString = inetAddr.getHostAddress();
byte ipAddress[] = inetAddr.getAddress();
boolean isLocalhost = inetAddr.isLoopbackAddress();



P2P Server sockets相比起標準的server socket來講,擁有一個有趣的問題。因爲P2P sockets系統本身實現了一個簡單的DNS system,咱們須要一種方法來創建一個InetAddress對象,即便此時主機名還並不存在;明確的一點是咱們並不想搜索整個網絡來將給定的主機名解析爲IP地址,反之亦然,也是因爲兩者可能都不存在。咱們可能會使用InetAddress對象來將一個P2PServerSocket綁定到一個新的主機名和IP地址上。P2P Sockets目前重載了標準的getByAddress(String host,byte address[])方法來避免對沒有給定的信息解析。因爲對於這種信息的解析是沒有意思並且是沒必要要的,因此這種方法在建立一個P2PInetAddress的對象時是值得推薦的。要檢查指定的主機名或是IP地址是否已經被佔用,可使用P2PNameService類的方法,具體的使用方法在上一章已經介紹過了。

InetAddress對象能夠再啓動P2P Sockets和Server Sockets時使用,就和使用標準的Java Sockets和server Sockets同樣:

InetAddress inetAddr = P2PInetAddress.getByAddress("www.boobah.cat", null);
ServerSocket server = new P2PServerSocket(inetAddr, 80);
.......
.......
.......
InetAddress inetAddr = P2PInetAddress.getByAddress("www.boobah.cat", null);
Socket server = new P2PSocket(inetAddr, 80);



本地環回(127.0.0.1)地址和任播地址(0.0.0.0)
P2P Sockets包提供了一個廣播地址的簡單實現,這個地址就是0.0.0.0。在標準的TCP/IP Server Sockets使用方法當中,對於廣播的接口是這樣介紹的「對於本機上任意一個可用的IP地址啓動server socket;不須要知道這個IP地址具體是什麼。」在P2P Server Sockets的環境當中,一個主機不能是「multi-home」的,也就是說,就是不能有多餘一個的IP地址。取而代之的是,server socket會被指定一個自動生成的主機名,也就是它的JXTA peer名。舉例來講,若是一個peer的名字叫作BradGNUberg,這個peer被給定了一個自動生成的主機名www.BradGNUberg.peer。 缺省情況下,前綴是「www.」,後綴是「.peer」。這些值目前是不能自定義的,但在將來的版本當中會給出這種能力。

咱們使用自動生成的Peer名來解析廣播和環回地址:

// In the following example, assume the peer's
// local JXTA name is BradGNUberg.
InetAddress inetAddr = P2PInetAddress.getLocalHost();
ServerSocket socket = new P2PServerSocket(inetAddr, 100);
// returns "www.BradGNUberg.peer"
String hostName = socket.getHostName();




在這段代碼運行以前,你必須在localhost和指定端口上啓動一個P2PServerSocket。

P2P Server Socket一樣提供和標準server sockets相兼容的另外一種特性,儘管這個特性可能不多會被使用。標準的TCP/IP server Socket能夠在不指定端口的狀況下被啓動。這種狀況下會啓動一個server socket使用隨機的「私有」端口about 1024(不知道什麼意思)。P2PSocket一樣支持了這個功能;若是你啓動一個server socket而沒有指定主機名,廣播接口,或是端口號,一個隨機的端口號會在1024和65535之間產生。你能夠從server socket上得到這個端口號,而後使用其餘的途徑通知客戶端socket,告訴它一個私有的,隨機的端口好已經可使用了。

侷限性和安全問題

P2P sockets 工程目前有一下的侷限性和安全問題:
●假冒主機名和IP地址的狀況在peer當中比較少見,因此如今尚未一種機制用於將指定的主機名和IP地址安全的聯繫到特定peer或是peer group上。
●網絡容易收到DOS(denial-of-service)攻擊,當一個peer在網絡中大量發送請求或是不斷的創建server sockets。
●P2P Socket 報尚未被綁定到JVM Security Manager architecture(JVM安全管理架構)當中,在這個框架之中代碼會被根據安全策略放到沙箱之中。一旦一個peer被暴露在網絡當中,其餘的peer能夠利用Java虛擬機的缺陷或是P2P Socket層自己的缺陷來危及這個peer的安全。將peer的代碼放到沙箱裏面和本地機器的資源格離起來能夠保護這個缺陷,但因爲P2P Socket在執行以前並不檢查安全管理,因此目前這種方法還不可行。將JSP引擎包含在標準的我的電腦上,例如JSP依賴於javac,java編譯器上一樣是很危險的。將網絡路徑包含在一種語言的編譯器當中也很危險,這是一種攻擊計算機取得更高的訪問權的經常使用方式。你應該預先編譯好你的JSP和servlet,並將它們綁定到你的peer程序當中而不是提供整個的JSP引擎。
●還不支持多播IP地址和多播Socket。
●還不支持UDP Socket。
●一些socket選項,流入SoLinger,並無被支持。
●不支持非阻塞的I/O Socket 管道
●本機的環回socket服務器被暴露給外界,這是不對的。
●不支持SSL/HTTPS
●JXTA的配置器在沒有JXTA配置的時候會被激活。這帶來了幾個問題。首先,這是P2P Sockets暴露給程序員JXTA概念的最後一個地方,其次,它要求用戶深刻了解這個配置系統以查找出他是否處在防火牆或是NAT設備以後。將來的工程會自動配置這些屬性,加入一種「內省」的方法,來自我感知是否處在防火牆或是NAT設備以後。


版權信息:P2P Socket,包括本文的源代碼,都受Sun Project JXTA Software License的保護。

相關文章
相關標籤/搜索