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完全一样。

// 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.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。

最终的代码如下所示:
1
2
3 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);      }   }}
4



使用P2P Socket来连接P2P Server Socket

建立和使用P2P socket连接P2P Server socket一样容易:
首先,需要登录进去指定的peer-to-peer网络当中:

// 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:

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的保护。

资源
●"How to Create Peer-to-Peer Web Servers, Servlets, JSPs, and XML-RPC Clients and Servers"
●P2P Sockets主页
●JXTA主页
●JXTA配置器
●"What is a WikiWiki?"
●JDK 1.4
●Ant 1.5.3
●P2PSockets-1.0-beta1.zip
●Brad GNUberg的Weblog
●给Brad GNUberg发邮件

问题?评论?
请查阅P2P Sockets Homepage或和作者Brad Neuberg联系。或在太平洋标准时间,从周一到周五拨打1(510) 938-3263。或者查看他的网志,www.codinginparadise.org,获得关于Mozilla,Java,JXTA和P2P的新闻。

Brad Neuberg是一个开源开发者,目前居住在San Francisco

你可能感兴趣的:(socket)