————————————————————————————————————————————————————————————
![ONJava.com](http://onjava.com/images/onjava/onjava_logo.jpg)
Published on ONJava.com (http://www.onjava.com/)
See this if you're having trouble printing code examples
Introduction to the Peer-to-Peer Sockets Project
by Brad Neuberg12/03/2003
The Peer-to-Peer (P2P) Sockets Project reimplements Java's standard Socket
, ServerSocket
, and InetAddress
classes to work on the JXTA peer-to-peer network, rather than on the standard TCP/IP network. It also includes ports of many popular web packages, such as the Jetty web server, the Apache XML-RPC client and server libraries, and the Apache Jasper JSP engine, to run on the Peer-to-Peer Sockets framework.
By the end of this article, you will understand the motivation and need for the P2P Sockets package, how to configure and set up the P2P Socket libraries to run on your system, how to create and run P2P server and client sockets, how to work with the P2P InetAddress
class, and security issues and limitations in the framework.
Motivation
The P2P Sockets project is designed for developers interested in:
Returning the end-to-end principle to the Internet.
An alternative peer-to-peer domain name system that bypasses ICANN and Verisign, is completely decentralized, and responds to updates much quicker than standard DNS.
An Internet where everyone can create and consume network services, even if they have a dynamic IP address or no IP address, are behind a Network Address Translation (NAT) device, or blocked by an ISP's firewall.
A Web where every peer can automatically start a web server, host an XML-RPC service, and more, and quickly make these available to other peers.
Easily adding peer-to-peer functionality to Java socket and server socket applications.
Having servlets and Java Server Pages work on a peer-to-peer network for increased reliability, easier maintenance, and exciting new end-user functionality.
Playing with a cool technology.
The P2P Sockets project reimplements the standard java.net
classes on top of the JXTA peer-to-peer network. "Aren't standard TCP/IP sockets and server sockets already peer-to-peer?" some might ask. Standard TCP/IP sockets and server sockets are theoretically peer-to-peer, but in practice are not, due to firewalls, NAT devices, and political and technical issues with the Domain Name System (DNS). First, many of the peers on the Internet are given dynamic IP addresses through DHCP, shared or filtered IP addresses through NAT devices, or IP addresses that are very hard to reach due to firewalls. Creating server sockets under such conditions is either impossible or requires elaborate application-level ruses to bypass these restrictions. Second, TCP/IP sockets and server sockets depend on DNS to resolve human-friendly host names into IP addresses. DNS is theoretically semi-decentralized, but on an administrative level, it is centralized under ICANN, an unresponsive, non-innovative organization. Further, standard DNS does not deal well with edge-peers that have filtered or dynamic IP addresses, and updates take too long to propagate and have no presence information. Developers who wish to create exciting, new applications that extend DNS into new directions, such as storing instant messaging usernames and presence info in DNS, are stymied by the DNS system's technical and political issues.
Related Reading ![]() JXTA in a Nutshell |
JXTA is an open source project that creates a peer-to-peer overlay network that sits on top of TCP/IP. Every peer on the network is given an IP-address-like number, even if they are behind a firewall or don't have a stable IP address. Super-peers on the JXTA network run application-level routers that store special information such as how to reach peers, how to join subgroups of peers, and what content peers are making available. JXTA application-level relays can proxy requests between peers that would not normally be able to communicate due to firewalls or NAT devices. Peers organize themselves into peer groups, which scope all search requests and act as natural security containers. Any peer can publish and create a peer group in a decentralized way, and other peers can search for and discover these peer groups using other super-peers. Peers communicate using pipes, which are very similar to Unix pipes. Pipes abstract the exact way in which two peers communicate, allowing peers to communicate using other peers as intermediaries if they normally would not be able to communicate due to network partitioning.
JXTA is an extremely powerful framework. However, it is not an easy framework to learn, and porting existing software to work on JXTA is not for the faint-of-heart. P2P Sockets effectively hides JXTA by creating a thin illusion that the peer-to-peer network is actually a standard TCP/IP network. If peers wish to become servers, they simply create a P2P server socket with the domain name they want, and the port other peers should use to contact them. P2P clients open socket connections to hosts that are running services on given ports. Hosts can be resolved either by domain name, such as www.nike.laborpolicy
, or by IP address, such as 44.22.33.22
. Behind the scenes, these resolve to JXTA primitives, rather than being resolved through DNS or TCP/IP. For example, the host name www.nike.laborpolicy
is actually the NAME
field of a JXTA peer group advertisement. P2P sockets and server sockets work exactly the same as normal TCP/IP sockets and server sockets. For the technically inclined and those who already understand JXTA, a table exists illustrating how standard TCP/IP concepts such as host name, IP address, etc., map to their JXTA equivalents.
The benefits of taking this approach are many-fold. First, programmers can easily leverage their knowledge of standard TCP/IP sockets and server sockets to work on the JXTA peer-to-peer network without having to learn about JXTA. Second, all of the P2P Sockets code subclasses standard java.net
objects, such as java.net.Socket
, so existing network applications can quickly be ported to work on a peer-to-peer network. The P2P Sockets project already includes a large amount of software ported to use the peer-to-peer network, including a web server (Jetty) that can receive requests and serve content over the peer-to-peer network; a servlet and JSP engine (Jetty and Jasper) that allows existing servlets and JSPs to serve P2P clients; an XML-RPC client and server (Apache XML-RPC) for accessing and exposing P2P XML-RPC endpoints; an HTTP/1.1 client (Apache Commons HTTP-Client) that can access P2P web servers; a gateway (Smart Cache) to make it possible for existing browsers to access P2P web sites; and a WikiWiki (JSPWiki) that can be used to host WikiWikis on your local machine that other peers can access and edit through the P2P network. Even better, all of this software works and looks exactly as it did before being ported. The P2P Sockets abstraction is so strong that porting each of these pieces of software took as little as 30 minutes to several hours. Everything included in the P2P sockets project is open source, mostly under BSD-type licenses, and cross-platform due, to being written in Java.
Because P2P Sockets are based on JXTA, they can easily do things that ordinary server sockets and sockets can't handle. First, creating server sockets that can fail-over and scale is easy with P2P Sockets. Many different peers can start server sockets for the same host name and port, such as www.nike.laborpolicy
on port 80
. When a client opens a P2P socket to www.nike.laborpolicy
on port 80
, it will randomly connect to one of the machines that is hosting this port. All of these server peers might be hosting the same web site, for example, making it very easy to partition client requests across different server peers or to recover from losing one server peer. This is analogous to DNS round-robin, where one host name will resolve to many different IP addresses to help with load balancing. Second, since P2P Sockets don't use the DNS system, host names can be whatever you wish. You can create your own fanciful endings, such as www.boobah.cat
or www.cynthia.goddess
, or application-specific host names, such as Brad GNUberg
or Fidget666
for an instant messaging system. Third, the service ports for a given host name can be distributed across many different peers around the world. For example, imagine that you have a virtual host for www.nike.laborpolicy
. One peer could be hosting port 80
to serve web pages, another could be hosting port 2000
for instant messaging, and a final peer could be hosting port 3000
for peers to subscribe to real-time RSS updates. Hosts now become decentralized coalitions of peers working together to serve requests.
|
Requirements and Configuration
You must download and install the following software to develop and work with P2P Sockets.
JDK 1.4+
P2P Sockets only works with versions of the JDK after 1.4, because P2P Sockets subclassesjava.net.InetAddress
. Prior to 1.4, this class was markedfinal
and could not be subclassed.Ant 1.5.3+
Used to both build and run P2P Sockets and extensions such as Jetty and Jasper.P2PSockets-1.0-beta1.zip
The latest release of the P2P Sockets package.
Install and configure the JDK and Ant, and make sure both are in your path so they can be run from the command line. Unzip P2PSockets-1.0-beta1.zip
into the top level of your hard drive; spaces are not allowed in the directory names, or the P2P Sockets build files will not work correctly.
You must also add the JAR file p2psockets/lib/ant-contrib-0.5.jar
to your CLASSPATH
. On Windows this would look as follows:
set CLASSPATH=%CLASSPATH%;c:\p2psockets\lib\ant-contrib-0.5.jar
The P2P Sockets directory already includes two different directories, test/clientpeer and test/serverpeer, that have JXTA configuration information already set up (these are in the hidden directories test/clientpeer/.JXTA and test/serverpeer/.JXTA, respectively). If you want to learn more about how to configure JXTA, read about the JXTA Configurator. The two test peers have already been configured for the worst possible case, which is that you are behind a firewall and a NAT device, which means you must use other intermediate peers to relay your requests; this configuration will work even if you are not under these conditions. One of the nice aspects about JXTA, though, is that this will all be transparent and hidden from you as you program and use the system.
When testing the examples in this tutorial, you must be connected to the Internet. This is for two reasons: first, the examples use a public JXTA server Sun has set up that helps bootstrap peers into the JXTA network; and second, on some operating systems (such as on Windows XP, by default), the network subsystem shuts down if you are not connected to the Internet, preventing client peers and server peers that are running on the same machine from finding or communicating with each other.
Creating a P2P Server Socket
Creating a P2P server socket is exactly like creating a normal 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);
This creates a server socket listening for client requests for the host www.nike.laborpolicy
on port 100
. Under the covers, the P2PServerSocket code searches for a JXTA peer group named www.nike.laborpolicy
. If it finds this peer group, it joins it; otherwise it creates the group by publishing a JXTA peer group advertisement with the Name
field formatted in a certain way. This field always has the format hostname/IP address
, such as www.nike.laborpolicy/44.33.67.22
. We search based on host name or IP address on JXTA rendezvous servers by using wildcards, such as www.nike.laborpolicy/*
to search without having to know the IP address, or */44.33.67.22
to search for a peer group with the given IP address. Once we have found or created the host's peer group, we then publish a JXTA pipe advertisement into this peer group with the Name
field set to the port number, such as <Name>80</Name>
.
After creating this server socket, you can now treat it as an ordinary java.net.ServerSocket
in your code, waiting for a client and then retrieving an InputStream
and OutputStream
from the client and communicating normally:
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);
Even though the client looks like a normal java.net.Socket
, it is actually connecting and communicating to your server through the JXTA peer-to-peer network, with requests and responses possibly being relayed by other peers to traverse NATs and network partitions. All of this is hidden from you, however.
Unlike normal server sockets, we need to initialize and sign into our peer-to-peer network. Before you can create the P2PServerSocket
, therefore, you must sign in:
// 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");
The first two arguments are the username and password to use when signing into the peer-to-peer network. These are entered by the user when they set up the JXTA Configurator, a Swing dialog (which will pop up the first time you run the JXTA platform) that allows you to configure your peer on the P2P network. In your own application, you might retrieve these values either from the command line or from a GUI. The P2P Sockets package comes preconfigured with two JXTA peers already configured, located in test/clientpeer and test/serverpeer.
The final value (TestNetwork
, in the above example) is a unique name that will be given to your peer-to-peer network. Different peer-to-peer networks that are based on P2P Sockets can co-exist without knowing about each other. Clients and servers create and resolve their server sockets and sockets in a specific peer-to-peer network. The final value is the name of your own private, application-specific peer-to-peer network. If you create your server socket in the peer-to-peer network named TestNetwork
while a client signs into another peer-to-peer network named InstantMessagingNetwork
, then they will not be able to find each other or communicate.
Here's what is happening inside of the P2PNetwork
class. When you call the signin
method, the network string (TestNetwork
in the example given) is hashed into an MD5 peer group ID; this ensures that the application name given is globally unique if we search based on the peer group ID. We then search for this peer group, and create it if it does not exist. All domain name and IP address resolutions now occur inside of this application peer group. Note that the default JXTA configuration files included in test/clientpeer and test/serverpeer are configured to use the Sun rendezvous servers to bootstrap into the JXTA network; you should configure your own peers differently if you want them to use a different beginning rendezvous server when bootstrapping into the JXTA Net Peer Group.
As a programmer, you will choose your network name to go along with the name of your application or the type of network you are creating, such as MyApplicationsNetwork
or AcmeCompanyInformationNetwork
.
The final code looks as follows:
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); } } }
|
Using a P2P Socket to Contact a P2P Server Socket
Creating and using a P2P socket to connect to the P2P server socket you created is just as easy.
First, sign into your peer-to-peer network:
// 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");
Next, create your P2P socket with the host name and port to which you want to connect:
// create a socket to connect to the domain // "www.nike.laborpolicy" on port 100 java.net.Socket socket = new java.net.P2PSocket("www.nike.laborpolicy", 100);
Now you can easily communicate with the server:
// now communicate with this server 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!");
Here is the full source code for the client:
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); } } }
Running the P2P Server Socket and Socket Examples
Open two separate shell windows. In both windows, type the following to set some system variables needed by the Ant makefiles (modify the variables below to point to where you have installed P2P Sockets and your JDK, respectively):
set p2psockets_home=c:\p2psockets set JAVA_HOME=c:\j2sdk1.4.1
In both windows, change to the p2psockets directory where you installed the P2P Sockets package. The example source files are in p2psockets/src/examples and are named ExampleClientSocket.java and ExampleServerSocket.java, respectively. Everything has already been compiled into the p2psockets/dist/examples directory, but if you want to compile them again, enter the following in one of the two shells:
ant clobber build jar
To run the client and server, in one window enter the following to start the example P2P server socket:
ant example-serversocket-run
You should see the following printed in the server peer window:
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...
In the other window, enter the following to start the example P2P client socket:
ant example-clientsocket-run
You should see the following printed in the client peer window:
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!
In the server window, you should now see the following:
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!
Congratulations! You've just created a simple peer-to-peer network with very little work or extra knowledge needed above understanding basic Java sockets and server sockets.
If you have trouble, ensure that you are connected to the Internet, that you are running Java 1.4+, and that you did not install the P2P Sockets package into a directory with spaces in its name (such as in Program Files/p2psockets). You might also have to delve into the JXTA Configurator if your machine is in an unusual network configuration. If you are attempting to run the client and server P2P socket examples across separate machines that are blocked by NAT devices, you might run into an open bug that P2P Sockets currently has.
Finding Out if a Host Name, IP Address, or Port is Taken
By default, the P2PInetAddress
and P2PServerSocket
classes don't check to make sure a given host name, IP address, or port is taken. The reason for this is so that application developers can use P2P server sockets in unique ways that are not possible with normal sockets. For example, different peers can start up P2P server sockets for the same host name and port in order to provide failover and scalability. If we were to throw an exception when a server socket was started because the address was already bound, then this possibility would be precluded.
However, methods are provided to check if a given host name, IP address, or port is already taken. These are static methods on the class java.net.P2PNameService
. Examples are shown below:
boolean nameAvailable = P2PNameService.isHostNameTaken("www.nike.laborpolicy"); boolean portAvailable = P2PNameService.isPortTaken("www.nike.laborpolicy", 80); boolean addressAvailable = P2PNameService.isIPAddressTaken("33.44.74.12");
Use these before creating your P2P server sockets if you want your server to be a unique instance (read the Limitations and Security Concerns section, though, on P2P domain-name spoofing).
You have now learned the bulk of working with P2P sockets and server sockets. The following sections detail technical information on how the P2P Sockets package provides full compatibility with standard TCP/IP sockets and server sockets. You don't necessarily need to know this information, but should know it if you will be working with the InetAddress
class or the Loopback (127.0.0.1
) or Any (0.0.0.0
) addresses. If you skip these sections, please make sure to read the section Limitations and Security Concerns at the end of this article.
|
Working with the P2P InetAddress
Class
The P2P Sockets package includes an implementation of java.net.InetAddress
that works the same as InetAddress
and that subclasses it.
The following examples show different ways in which to create a P2PInetAddress
object.
// 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();
Once you have an P2PInetAddress
object, you can treat it like a normal InetAddress
object:
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 have an interesting problem that standard server sockets do not have. Because the P2P Sockets system implements its own simple DNS system, we need a way to create an InetAddress
for a host name that does not exist yet; we explicitly don't want to search the network to resolve a given host name into an IP address, or vice versa, because neither of them exist yet. We would then use this InetAddress
object to instantiate a P2PServerSocket
to bind a new host name and IP address. P2P Sockets currently overloads the standard getByAddress(String host, byte address[])
method to avoid resolving information that is not given. This is the recommended method to use to generate a P2PInetAddress
object, since contacting the network to resolve the extra information is wasteful and not really needed. To check to see if a given host name or IP address is already taken, use the methods on the P2PNameService
class, which were detailed in the section above:
InetAddress
objects can be used to start P2P sockets or server sockets, just as in standard Java sockets and 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);
The Loopback (127.0.0.1
) and Any (0.0.0.0
) Addresses
The P2P Sockets package provides a simple implementation of the Any IP address, which is 0.0.0.0
. In normal TCP/IP parlance for server sockets, the Any interface says "start a server socket with any of the available IP addresses available on this machine; I don't know which it is and don't care." In the context of P2P Server Sockets, hosts can not be "multi-homed;" i.e., have more than one IP address. Instead, they are given an automatic host name that is autogenerated from their JXTA peer names. For example, if a peer is named BradGNUberg
, then the peer would be given the automatic host name www.BradGNUberg.peer
. By default, the prefix is "www." and the suffix is ".peer". These values are currently not customizable, but future versions will expose this capability.
We use this automatic peer name to resolve the Any or Loopback address:
// 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();
Before this will work, however, you must start up a P2PServerSocket
for the localhost on a given port.
P2P server sockets also provides support for another feature for compatibility with normal server sockets, though it will probably only rarely be used. Normal TCP/IP server sockets can be started with the any interface and no port specified. This would start the server socket on a random "private" port about 1024
. The P2PServerSocket
class supports the same thing; if you start it with no host name or the Any interface and no port, a random port number will be generated above 1024
but less than 65536
. You could then retrieve this port number from the server socket and send it to client sockets over another channel to inform them of a private, random port that is available.
Limitations and Security Concerns
The P2P Sockets project currently has the following limitations and security issues:
The P2P Sockets package does not currently tie into the JVM Security Manager architecture, which would sandbox the code according to a security policy. Once a peer is exposed on a network, other peers could take advantage of flaws in the Java Virtual Machine or the P2P Sockets layer itself to compromise the peer computer. Being able to sandbox the peer code away from native machine resources would help this, but is not currently possible, since P2P Sockets doesn't check the security manager before any operation. It is also dangerous to include a JSP engine on an ordinary user's personal computer, as JSP depends on
javac
, the Java compiler. It is dangerous to include a network path to a language compiler, as this is a common way to compromise a computer and gain further access. You should precompile your JSPs into servlets and bundle the servlets with your peer programs instead of the full JSP engine.Multicast IP addresses and Multicast sockets are not supported.
UDP sockets are not supported.
Site-local/private IP addresses (
192.168.x.x
) are not supported. Create your own private peer group if you want to simulate a private site address.The various socket options, such as
SoLinger
, are not supported and are ignored.Non-blocking I/O socket channels are not supported.
Loopback socket servers are exposed outside of their local machine, which is incorrect.
SSL/HTTPS is not supported.
The JXTA Configurator is still invoked if there is no JXTA configuration. This has several problems. First, it is one of the last pieces of P2P Sockets that exposes programmers to JXTA concepts, and second, it requires users to delve into a complex configuration system to figure out if they are behind a firewall or NAT device. A future project will address autoconfiguring these properties by having the peer "introspect" itself to see if it is behind a firewall, a NAT device, etc.
License Information
P2P Sockets, including the source code in this article, is under the Sun Project JXTA Software License.
Resources
- "How to Create Peer-to-Peer Web Servers, Servlets, JSPs, and XML-RPC Clients and Servers"
- P2P Sockets Homepage
- JXTA Homepage
- The JXTA Configurator
- "What is a WikiWiki?"
- JDK 1.4
- Ant 1.5.3
- P2PSockets-1.0-beta1.zip
- Brad GNUberg's Weblog
- Email Brad GNUberg at bkn3@columbia.edu
Questions? Comments?
See the P2P Sockets Homepage or contact Brad Neuberg at bkn3@columbia.edu . Feel free to call him at 1 (510) 938-3263 (Pacific Standard Time, San Francisco) Monday through Friday, not including weekends. Also see his weblog, www.codinginparadise.org, for Mozilla, Java, JXTA, and P2P news.
Brad Neuberg has done extensive work in the open source community, contributing code to Mozilla, JXTA, the Jakarta Feed Parser, and more.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.
——————————————————————————————————————————————————————————————————————————
下面这个是翻译版:
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
作者:
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完全一样。
// 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。
最终的代码如下所示:
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网络当中:
// 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的保护。
傲轩游戏网