Weiter | Weiter | Weiter | Weiter | Kommentar

all-inOne, section 16.

16.  Networking

16.1.  Internet Addresses

Every Internet-connected system has a unique Internet host address.

This is a 32 bit, or 4 byte, binary number.

Internet addresses are written as a dotted sequence of the form:

a.b.c.d

where a, b, c and d etc, are the decimal values (ranging from 0 to 255) of the 4 bytes which make up the internet address, for example:

129.3.20.4

129.3.20.4 is the IP address of ilon,or to use its full name

yps.cs.rit.edu

We will later see how the name of a computer is mapped to its IP-address.

16.2.  IP Address Classes

[picture]

16.3.  Ethernet Address

An IP-address only makes sense to the TCP/IP suite. A data link such as an Ethernet or a token ring has its own addressing scheme (often 48 bits).

The-byte address is often used, which is divided into a 3-byte vendor ID and a 3-byte vendor-defined field. Ethernet manufacturers are assigned a unique vendor ID, and are then responsible for insuring that all of their devices have unique addresses in the last 3 bytes.

A network, such as an Ethernet can be used by different network layers at the same time. See also RFC 802.

16.4.  Encapsulation

When an application sends data using TCP is sent down the protocol stack.

A pyhsical proporty of an Ethernetframe is, that the size of its data must be between 46 and 1500 bytes.

[picture]

16.5.  TCP Ports

TCP is using protocl port numbers to indentify the ultimate destination.

How does one deteremine the port to communicate with?

--
Well known ports
--
Randomly assigned ports.

16.6.  Socket

Two popular Application Programming Interface using TCP/IP protocols are called sockets and TLI (transport layer interface).

A socket is one end-point of a two-way communication link between two programs running on the network. Socket classes are used to represent the connection between a client program and a server program. The java.net package provides two classes--Socket and ServerSocket--that implement the client side of the connection and the server side of the connection, respectively.

A socket is a network communications endpoint.

A socket is an object from which messages are sent and received.

Socket operations resemble file operations in many respects:

See also: java.net

16.7.  java.net

Through the classes in java.net, Java programs can use TCP or UDP to communicate over the Internet. The URL, URLConnection, Socket, and ServerSocket classes all use TCP to communicate over the network. The DatagramPacket, DatagramSocket, and MulticastSocket classes are for use with UDP.

16.8.  Getting Information

Host info

Src/16/HostInfo.java


import java.net.*;
import java.io.*;
import java.util.*;
public class HostInfo {
    public static void main(String argv[]) {
	InetAddress ipAddr;
	try {
		ipAddr = InetAddress.getLocalHost();
		System.out.println ("This is "+ipAddr);
	} catch (UnknownHostException e) {
		System.out.println ("Unknown host");
	}
    }
}

Source Code: Src/16/HostInfo.java

% java HostInfo
This is yps/129.21.38.198

Daytime Client

Src/16/DayTime.java


import java.net.*;
import java.io.*;
import java.util.*;
public class DayTime {

    String hostName = "yps";
    int    port = 13;

    private void printMessage()	{
	System.out.println("-h		---->	help");
	System.out.println("[-host 		hostName]");
	System.out.println("[-port 		port]");
   }
	
   /**
     * Parse the commandlind arguments and sets variables.
     */
   public void parseArgs(String args[]) {

	for (int i = 0; i < args.length; i ++) {
	   	if (args[i].equals("-h")) 
			printMessage();
	   	else if (args[i].equals("-host")) 
			hostName = args[++i];
	   	else if (args[i].equals("-port")) 
			port = new Integer(args[++i]).intValue();
	}
   }

   public void doTheJob()	{
	try {
		System.out.println("host: " +  hostName );
		System.out.println("port: " +  port );
		Socket sock = new Socket(hostName, port);
		
		BufferedReader din = new BufferedReader (
			new InputStreamReader (sock.getInputStream()));
		String rTime = din.readLine ();
		System.out.println (rTime);
		sock.close();
	} catch (Exception e) {
		System.out.println (e);
	}
   }

   public static void main(String argv[]) {
	DayTime aDayTime = new DayTime();
	aDayTime.parseArgs(argv);
	aDayTime.doTheJob();

   }
}

Source Code: Src/16/DayTime.java

% java DayTime  -host holly
host: holly
port: 13
Mon Apr 30 15:20:34 2001

Daytime Server

Src/16/DayTimeServer.java


import java.net.*;
import java.io.*;
import java.util.*;

public class DayTimeServer extends Thread {

   ServerSocket 	listen;
   static String 	hostName = "yps";
   int			port     = 4242;

   public DayTimeServer(int port)	{
   }

   public DayTimeServer(int port)	{
        try { 
            listen = new ServerSocket(port);
            System.out.println ("Listening on port: "
                + listen.getLocalPort());
        } catch(Exception e) {
            System.out.println(e);
        }
   }

    private void printMessage()	{
	System.out.println("-h		---->	help");
	System.out.println("[-host 		hostName");
	System.out.println(" -port 		port");
	System.out.println(" {-port 		port}");
	System.out.println("or ");
	System.out.println(" no argument");
   }
	
   /**
     * Parse the commandlind arguments and sets variables.
     */
   public void parseArgs(String args[]) {

	for (int i = 0; i < args.length; i ++) {
	   	if (args[i].equals("-h")) 
			printMessage();
	   	else if (args[i].equals("-host")) 
			hostName = args[++i];
	   	else if (args[i].equals("-port")) {
			port = new Integer(args[++i]).intValue();
			new DayTimeServer(port).start();
		}
	}
   }
   
   public void run()	{
        try {
            for(;;) {
                Socket clnt = listen.accept();
                System.out.println(clnt.toString());
                PrintWriter out = new PrintWriter
                    (clnt.getOutputStream (), true);
                out.println("It is now: " + new Date());
                clnt.close();
            }
        } catch(Exception e) {
            System.out.println(e);
	    e.printStackTrace();
        }
   }

    public static void main(String argv[]) {
	if ( argv.length == 0 )
		new DayTimeServer(0).start();
	else
		new DayTimeServer().parseArgs(argv);
    }
}

Source Code: Src/16/DayTimeServer.java

% # Window 1
java DayTimeServer -host yps -port 4242 -port 4243
Listening on port: 49154
Listening on port: 4242
Listening on port: 4243
listen = ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=4242]
listen = ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=4243]
Socket[addr=yps/129.21.38.198,port=49155,localport=4242]
Socket[addr=yps/129.21.38.198,port=49157,localport=4243]



% # Window 2
yps 16 100 ssh yps "cd `pwd` && java DayTime -port 4243"
host: yps
port: 4243
It is nowMon Apr 30 15:23:17 EDT 2001
% 

16.9.  Reading from and Writing to a Socket

Src/16/HpEchoSocketTest.java.minusSTART_STOP


import java.io.*;
import java.net.*;

class HpEchoSocketTest {

       Socket s;
       String hostname;
       int port;
       PrintWriter out = null;
        BufferedReader in = null;


       public void readAndPrint() throws Exception {
              InputStream ins;
              OutputStream os;

              BufferedReader stdIn = new BufferedReader(
                                   new InputStreamReader(System.in));
                String userInput;

                    while ((userInput = stdIn.readLine()) != null) {
                        out.println(userInput);
                        System.out.println("echo: " + in.readLine());
                    }
              stdIn.close();
       }

///////////////////////////////////////////////


       public HpEchoSocketTest(String name, int port) {
              hostname = name;
              this.port = port;
              try {
                     s = new Socket(hostname, port);
                     out = new PrintWriter(
                            s.getOutputStream(), true);
                        in = new BufferedReader(
                              new InputStreamReader(
                                          s.getInputStream()));
                     readAndPrint();
                     in.close();
                     out.close();
              } catch (Exception e )       {
                     System.out.println(e.toString());
                     System.exit(1);
              }
       }

       public static void main(String[] args) {
              HpEchoSocketTest st;
              String host = "holly";
              int    port = 7;

              st = new HpEchoSocketTest(host, port);
       }

}

Source Code: Src/16/HpEchoSocketTest.java

This client program is straightforward and simple because the Echo server implements a simple protocol. The client sends text to the server, and the server echoes it back.

These are the typical steps:

1.
Open a socket.
2.
Open an input stream and output stream to the socket.
3.
Read from and write to the stream according to the server's protocol.
4.
Close the streams.
5.
Close the socket.

16.10.  Connection to an URL

Class URL represents a Uniform Resource Locator, a pointer to a "resource" on the World Wide Web. A resource can be something as simple as a file or a directory, or it can be a reference to a more complicated object, such as a query to a database or to a search engine. More information on the types of URLs and their formats can be found at: http://www.ncsa.uiuc.edu/demoweb/url-primer.html

Src/16/Url_Read.java


import java.io.*;
import java.net.URL;
import java.net.MalformedURLException;

public class Url_Read {

  public static void readFromUrl(String theUrl) {
  
  URL aUrl = null;
  BufferedReader in = null;
  String line;
  
  try {
	  aUrl = new URL(theUrl);
	  System.out.println("getPort() " + aUrl.getPort());
	  System.out.println("getHost() " + aUrl.getHost());
	  System.out.println("getProtocol() " + aUrl.getProtocol());
	  System.out.println("getFile() " + aUrl.getFile());
	  System.out.println("getRef() " + aUrl.getRef());

	  in = new BufferedReader(
		   new InputStreamReader( aUrl.openStream() ) );

	  while ( ( line = in.readLine() ) != null ) {
		System.out.println(line);
	  }

	  in.close();
	  
  } catch (MalformedURLException e) {
	  System.err.println("Something is wrong with this " +
		theUrl +  ".");
	  System.exit(1);
  } catch (IOException e) {
	  System.err.println("Couldn't get I/O for the connection to: "
		+ theUrl );
	  System.exit(1);
  }
  
  }

  public static void main( String args[] ) {

    if ( args.length != 1 )	{
	System.err.println(
	     "Usage: java Url_Read url");
	System.exit(1);
    }

    try {
	readFromUrl(args[0]);
	
    }
    catch ( NumberFormatException e)	{
    	System.out.println(args[0] + " is not a number ;-(");
    }

  }
}

Source Code: Src/16/Url_Read.java

% java Url_Read http://www.cs.rit.edu/~hpb | sed 15q
getPort() -1
getHost() www.cs.rit.edu
getProtocol() http
getFile() /~hpb
getRef() null
<HTML>

<HEAD>
<title>Hans-Peter Bischof's Home Page</title>
</HEAD>


<FRAMESET cols="230,*">
  <frame name="toc"    TARGET="_main" src="toc.html"     scrolling="auto">
  <frame name="intro"                 src="intro.html"   scrolling="auto">

16.11.  Multi Client Server and Client

16.12.  Datagram Socket

An example:

Src/16/DayTimeUDPServer.java


import java.net.*;
import java.io.*;
import java.util.*;

public class DayTimeUDPServer extends Thread {

   DatagramSocket 	socket;
   static String 	hostName = "yps";
   int			port     = 4242;


   public DayTimeUDPServer()	{
   }

   public DayTimeUDPServer(int port)	{
        try { 
            socket = new DatagramSocket(port);
            System.out.println ("Listening on port: "
                + socket.getLocalPort());
        } catch(Exception e) {
            System.out.println(e);
        }
   }

    private void printMessage()	{
	System.out.println("-h		---->	help");
	System.out.println("[-host 		hostName");
	System.out.println(" -port 		port");
	System.out.println(" {-port 		port}");
	System.out.println("or ");
	System.out.println(" no argument");
   }
	
   /**
     * Parse the commandlind arguments and sets variables.
     */
   public void parseArgs(String args[]) {

	for (int i = 0; i < args.length; i ++) {
	   	if (args[i].equals("-h")) 
			printMessage();
	   	else if (args[i].equals("-host")) 
			hostName = args[++i];
	   	else if (args[i].equals("-port")) {
			port = new Integer(args[++i]).intValue();
			new DayTimeUDPServer(port).start();
		}
	}
   }
   
   public void run()	{
        byte[] buf = new byte[256];
        try {
            for(;;) {
		String sendThis = "es schlaegt: " + new Date();
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
		socket.receive(packet);
                InetAddress address = packet.getAddress();
                int port = packet.getPort();
		buf = sendThis.getBytes();
                packet = new DatagramPacket(buf, buf.length, address, port);
		System.out.println("Sending to port: " + port );
		System.out.println("Sending    data: " + new String(buf) );
                socket.send(packet);
            }
        } catch(Exception e) {
            System.out.println(e);
	    e.printStackTrace();
        }
   }

    public static void main(String argv[]) {
	if ( argv.length == 0 )
		new DayTimeUDPServer(0).start();
	else
		new DayTimeUDPServer().parseArgs(argv);
    }
}

Source Code: Src/16/DayTimeUDPServer.java

Src/16/DayTimeUDP.java


import java.net.*;
import java.io.*;
import java.util.*;
public class DayTimeUDP {

    String hostName = "yps";
    int    port = 13;

    private void printMessage()	{
	System.out.println("-h		---->	help");
	System.out.println("[-host 		hostName]");
	System.out.println("[-port 		port]");
   }
	
   /**
     * Parse the commandlind arguments and sets variables.
     */
   public void parseArgs(String args[]) {

	for (int i = 0; i < args.length; i ++) {
	   	if (args[i].equals("-h")) 
			printMessage();
	   	else if (args[i].equals("-host")) 
			hostName = args[++i];
	   	else if (args[i].equals("-port")) 
			port = new Integer(args[++i]).intValue();
	}
   }

   public void doTheJob()	{
	try {
		byte buf[] = new byte[64];
		InetAddress aInetAddress = InetAddress.getByName(hostName);
		DatagramPacket dp = new DatagramPacket(buf, buf.length);
		DatagramSocket socket = new DatagramSocket();
		DatagramPacket packet = new DatagramPacket(buf,
			buf.length, aInetAddress, port);
		socket.send(packet);

		System.out.println("host: " +  hostName );
		System.out.println("port: " +  port );
		System.out.println("after creation");
		socket.receive(dp);
		System.out.println("received: -" +
			new String(dp.getData() ) + "-"  );
		socket.close();
	} catch (Exception e) {
		System.out.println (e);
		e.printStackTrace();
	}
   }

   public static void main(String argv[]) {
	DayTimeUDP aDayTimeUDP = new DayTimeUDP();
	aDayTimeUDP.parseArgs(argv);
	aDayTimeUDP.doTheJob();

   }
}

Source Code: Src/16/DayTimeUDP.java

16.13.  Remote Method Invocation

See also http://java.sun.com/docs/books/tutorial/rmi.

Part of the text and programs are from there. Copyright belongs to Ann Wollrath and Jim Waldo.

See also http://java.sun.com/products/jdk/1.2/docs/guide/rmi/.

The Java Remote Method Invocation (RMI) system allows an object running in one Java Virtual Machine (VM) to invoke methods on an object running in another Java VM. RMI provides for remote communication between programs written in the Java programming language.

Distributed object applications need to:

Locate remote objects

Applications can use one of two mechanisms to obtain references to remote objects. An application can register its remote objects with RMI's simple naming facility, the rmiregistry, or the application can pass and return remote object references as part of its normal operation.
Communicate with remote objects

Details of communication between remote objects are handled by RMI; to the programmer, remote communication looks like a standard Java method invocation.
Load class bytecodes for objects that are passed as parameters or return values

Because RMI allows a caller to pass pure Java objects to remote objects, RMI provides the necessary mechanisms for loading an object's code as well as transmitting its data.

The illustration below depicts an RMI distributed application that uses the registry to obtain references to a remote object. The server calls the registry to associate a name with a remote object. The client looks up the remote object by its name in the server's registry and then invokes a method on it. The illustration also shows that the RMI system uses an existing web server to load Java class bytecodes, from server to client and from client to server, for objects when needed. RMI can load class bytecodes using any URL protocol (e.g., HTTP, FTP, file, etc.) that is supported by the Java system.

16.14.  Passing Non-remote Objects

A non-remote object, that is passed as a parameter of a remote method invocation or returned as a result of a remote method invocation, is passed by copy; that is, the object is serialized using the Java Object Serialization mechanism.

So, when a non-remote object is passed as an argument or return value in a remote method invocation, the content of the non-remote object is copied before invoking the call on the remote object.

When a non-remote object is returned from a remote method invocation, a new object is created in the calling virtual machine

16.15.  Advantages of Dynamic Code Loading

16.16.  Remote Interfaces, Objects, and Methods

--
A remote interface extends the interface java/rmi.Remote.
--
Each method of the interface declares java/rmi.RemoteException in its throws clause, in addition to any application-specific exceptions.

16.17.  Creating Distributed Applications Using RMI

1.
Design and implement the components of your distributed application.
2.
Compile sources and generate stubs.
3.
Make classes network accessible.
4.
Start the application.

See also http://java.sun.com/products/jdk/1.2/docs/guide/rmi/spec/rmiTOC.doc.html

Compile Sources and Generate Stubs

This is a two-step process. In the first step you use the javac compiler to compile the source files, which contain the implementation of the remote interfaces and implementations, the server classes, and the client classes. In the second step you use the rmic compiler to create stubs for the remote objects. RMI uses a remote object's stub class as a proxy in clients so that clients can communicate with a particular remote object.

Make Classes Network Accessible

In this step you make everything--the class files associated with the remote interfaces, stubs, and other classes that need to be downloaded to clients.

Start the Application

Starting the application includes running the RMI remote object registry, the server, and the client.

16.18.  Intro Example

We have to design a protocol that allows jobs to be submitted to the server and results of the job to be returned to the client. This protocol is expressed in interfaces supported by the server and by the objects that are submitted to the sever, as shown in the following figure.

[picture]

16.19.  Hello World

The Client:

Src/16_D/HelloC.java


import java.rmi.*;

public class HelloC {
	public static void main(String args[] ) {
	String message = "";
	try {
		Hello obj =
			 (Hello)Naming.lookup("//yps/HelloServer");

		message = obj.sayHello();

		System.out.println(message);

	} catch (Exception e) {
		System.out.println("HelloC exception: " +
		e.getMessage());
		e.printStackTrace();
	}
  }
}

Source Code: Src/16_D/HelloC.java The interface:

Src/16_D/Hello.java


public interface Hello extends java.rmi.Remote {
        String sayHello() throws java.rmi.RemoteException;
}

Source Code: Src/16_D/Hello.java

The Server:

Src/16_D/HelloImpl.java.minusSTART_STOP


import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class HelloImpl
        extends UnicastRemoteObject
        implements Hello {
        private String name;

        public HelloImpl(String s) throws RemoteException {
		System.out.println(
		   "\tHelloImpl: HelloImpl(String s)");
                name = s;
        }

        public String sayHello() throws RemoteException {
                return  "Hello World my friend.";
        }

        public static void main(String args[])
        {
                System.setSecurityManager(new RMISecurityManager());

                try {
                    HelloImpl obj = new HelloImpl("HelloServer");
                    Naming.rebind("//yps/HelloServer", obj);
                    System.out.println("HelloServer bound in registry");
                } catch (Exception e) {
                    System.out.println("HelloImpl err: " + e.getMessage());
                    e.printStackTrace();
                }
        }
}

Source Code: Src/16_D/HelloImpl.java

RMISecurityManager

The RMISecurityManager class defines a default security policy for RMI applications (not applets). For code loaded from a class loader, the security manager disables all functions except class definition and access. This class may be subclassed to implement a different policy. To set a RMISecurityManager, add the following to an application's main() method:

System.setSecurityManager(new RMISecurityManager());

If no security manager has been set, RMI will only load classes from local system files as defined by CLASSPATH.

Policy Files

Here is a general policy file that allows downloaded code, from any code base, to do two things:

Here is the code for the general policy file:

        grant {
            permission java.net.SocketPermission "*:1024-65535",
                "connect,accept";
            permission java.net.SocketPermission "*:80", "connect";
        };

If you make your code available for downloading via HTTP URLs, you should use the preceding policy file when you run this example. However, if you use file URLs instead, you can use the following policy file.

Note that in Windows-style file names, the backslash character needs to be represented by two backslash characters in the policy file.

        grant {
            permission java.net.SocketPermission "*:1024-65535",
                "connect,accept";
            permission java.io.FilePermission
                "c:\home\hpb\public_html\classes\-", "read";
            permission java.io.FilePermission
                "c:\home\atk\public_html\classes\-", "read";
        };

This example assumes that the policy file is called java.policy and that it contains the appropriate permissions. If you run this example on JDK 1.1, you will not need to use a policy file, since the RMISecurityManager provides all of the protection you need.

Naming

is the bootstrap mechanism for obtaining references to remote objects based on Uniform Resource Locator (URL) syntax. The URL for a remote object is specified using the usual host, port and name:

rmi://host:port/name 
host = host

name of registry (defaults to the current host) port = port
number of registry (defaults to the registry port number) name = name
for remote object

The makefile:

 1      
 2      all:
 3        rmic HelloImpl
 4        rmiregistry &
 5        sleep 1
 6        javac HelloImpl.java
 7        java HelloImpl &
 8        sleep 4
 9        javac HelloC.java
10        java HelloC
11      

Source Code: Src/16_D/Makefile

% make -f Makefile
rmic HelloImpl
rmiregistry &
javac HelloImpl.java
java HelloImpl &
sleep 4
HelloServer bound in registry
javac HelloC.java
java HelloC
Hello World my friend.

Note: Make sure that rmiregistry is dead before you log out!

Note: Make sure that every java server is dead before you log out!

 1      #!/bin/sh
 2      
 3      TO_FIND="registry"
 4      if [ $# -eq 1 ]
 5      then
 6        if [ $1 -eq "java" ]
 7        then
 8          TO_FIND="java"
 9        fi
10      fi
11      
12      
13      ps -edf                 |       \
14      grep $TO_FIND           |       \
15      grep -v grep            |       \
16      grep -v kill            |       \
17      grep -v vi              |       \
18      awk ' { print $2 }'     |       \
19      while read x
20      do
21        echo "kill -9 $x"
22        kill -9 $x 2> /dev/null
23      done
24      
25      exit 0

Source Code: Src/16_D/killIt

% ps -edf | grep java

The improved makefile:

 1      
 2      
 3      all: HelloImpl_Skel.class HelloImpl_Stub.class  \
 4           Hello.class HelloC.class HelloImpl.class   
 5      
 6        rmiregistry &
 7        sleep 1
 8        java -Djava.security.policy=java.policy HelloImpl &
 9        sleep 4
10        java HelloC
11        # killIt java
12        # killIt
13        # make clean
14      
15      
16      HelloImpl_Skel.class HelloImpl_Stub.class: HelloImpl.java
17        rmic HelloImpl
18      
19      Hello.class:    Hello.java
20        javac Hello.java
21      
22      HelloC.class:   HelloC.java
23        javac HelloC.java
24      
25      HelloImpl.class:        HelloImpl.java
26        javac HelloImpl.java
27      
28      
29      clean:
30        rm -f *class
31      

Source Code: Src/16_D/makefile

% make
rmic HelloImpl
javac HelloC.java
rmiregistry &
sleep 1
java HelloImpl &
sleep 4
        HelloImpl: HelloImpl(String s)
HelloServer bound in registry
java HelloC
Hello World my friend.
killIt java
kill -9 26491
kill -9 26489
kill -9 26438
kill -9 26332
kill -9 26501
Killed
killIt 
Killed

The registry by default runs on port 1099. To start the registry on a different port, specify the port number in the command. For example, to start the registry on port 2001:

% rmiregistry 2001

For example, if the registry is running on port 2001 in the Hello World example, here is the call required to bind HelloServer to the remote object reference:

Naming.lookup("//yps:2001/HelloServer", obj);

16.20.  Hello World II

The Client:

Src/16_P/HelloC.java


import java.rmi.*;

public class HelloC {
	public static void main(String args[] ) {
	String message = "";
	try {
		Hello obj =
			 (Hello)Naming.lookup("//yps:2001/HelloServer");

		message = obj.sayHello();

		System.out.println(message);

	} catch (Exception e) {
		System.out.println("Something went wrong: " +
			e.getMessage());
		e.printStackTrace();
	}
  }
}

Source Code: Src/16_P/HelloC.java

The Server:

Src/16_P/HelloImpl.java


import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class HelloImpl
        extends UnicastRemoteObject
        implements Hello
{
        private String name;

        public HelloImpl(String s) throws RemoteException {
                name = s;
        }

        public String sayHello() throws RemoteException {
                return  "Stanley Kubrick was there!";
        }

        public static void main(String args[])
        {
                // Create and install a security manager
                // System.setSecurityManager(new RMISecurityManager());

                try {
                        HelloImpl obj = new HelloImpl("HelloServer");
                        Naming.rebind("//yps:2001/HelloServer", obj);
                        System.out.println("HelloServer bound in registry");
                } catch (Exception e) {
                        System.out.println("HelloImpl err: " + e.getMessage());
                        e.printStackTrace();
                }
        }
}

Source Code: Src/16_P/HelloImpl.java

The interface:

Src/16_P/Hello.java


public interface Hello extends java.rmi.Remote {
        String sayHello() throws java.rmi.RemoteException;
}

Source Code: Src/16_P/Hello.java

The makefile:

 1      
 2      
 3      all: Hello.class HelloC.class HelloImpl.class   \
 4           HelloImpl_Skel.class HelloImpl_Stub.class
 5      
 6        rmiregistry 2001 &
 7        sleep 1
 8        java HelloImpl &
 9        sleep 4
10        java HelloC
11        killIt java
12        killIt
13      
14      
15      HelloImpl_Skel.class HelloImpl_Stub.class: HelloImpl.java
16        rmic HelloImpl
17      
18      Hello.class:    Hello.java
19        javac Hello.java
20      
21      HelloC.class:   HelloC.java
22        javac HelloC.java
23      
24      HelloImpl.class:        HelloImpl.java
25        javac HelloImpl.java
26      
27      clean:  
28        rm -f *class

Source Code: Src/16_P/makefile

16.21.  Concurrency

Server:

Src/16_MultiA/HelloImpl.java.minusSTART_STOP


import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.*;

public class HelloImpl
        extends UnicastRemoteObject
        implements Hello {
        private String name;

        public HelloImpl(String s) throws RemoteException {
		System.out.println(
		   "\tHelloImpl: HelloImpl(String s)");
                name = s;
        }

        public String sayHelloAndWait() throws RemoteException {
		Date d;
		System.out.println("sayHelloAndWait: ---> ");
		System.out.println("\tSleeping .... ");
		for ( int index = 1; index < 100000; index ++ )
			d = new Date();
		System.out.println("\tGood morning");
		System.out.println("sayHelloAndWait: <-- ");
                return  "Hello World my friend.";
        }

        public synchronized String synchronizedSayHelloAndWait() throws RemoteException {
		Date d;
		System.out.println("synchronizedSayHelloAndWait: ---> ");
		System.out.println("\tSleeping .... ");
		for ( int index = 1; index < 100000; index ++ )
			d = new Date();
		System.out.println("\tGood morning");
		System.out.println("synchronizedSayHelloAndWait: <-- ");
                return  "Hello World my friend.";
        }

        public static void main(String args[])
        {
                // System.setSecurityManager(new RMISecurityManager());

                try {
                    HelloImpl obj = new HelloImpl("HelloServer");
                    Naming.rebind("//yps/HelloServer", obj);
                    System.out.println("HelloServer bound in registry");
                } catch (Exception e) {
                    System.out.println("HelloImpl err: " + e.getMessage());
                    e.printStackTrace();
                }
        }
}

Source Code: Src/16_MultiA/HelloImpl.java

Client:

Src/16_MultiA/HelloC.java.minusSTART_STOP


import java.rmi.*;

public class HelloC extends Thread {

	int id;

public HelloC(int id)
{
	this.id = id;
}

public void run () {
	String message = "";
	try {
		System.out.println("	" + id + " is in run.");
		Hello obj =
			 (Hello)Naming.lookup("//yps/HelloServer");

		if ( id % 2 == 0 )
			message = obj.sayHelloAndWait();
		else
			message = obj.synchronizedSayHelloAndWait();

		System.out.println(id + ": " + message);

	} catch (Exception e) {
		System.out.println("HelloC exception: " +
		e.getMessage());
		e.printStackTrace();
	}
}

public static void main(String args[] ) {
	for ( int i = 0; i < 10; i ++ )
		new HelloC(i).start();
  }
}

Source Code: Src/16_MultiA/HelloC.java

Client output:

yps 16_MultiA 184   java HelloC
       0 is in run.
        1 is in run.
        2 is in run.
        3 is in run.
        4 is in run.
        5 is in run.
        6 is in run.
        7 is in run.
        8 is in run.
        9 is in run.
sayHelloAndWait: ---> 
        Sleeping .... 
        Good morning
sayHelloAndWait: <-- 
0: Hello World my friend.
synchronizedSayHelloAndWait: ---> 
        Sleeping .... 
sayHelloAndWait: ---> 
        Sleeping .... 
sayHelloAndWait: ---> 
        Sleeping .... 
sayHelloAndWait: ---> 
        Sleeping .... 
sayHelloAndWait: ---> 
        Sleeping .... 
        Good morning
sayHelloAndWait: <-- 
2: Hello World my friend.
        Good morning
sayHelloAndWait: <-- 
8: Hello World my friend.
        Good morning
sayHelloAndWait: <-- 
4: Hello World my friend.
        Good morning
sayHelloAndWait: <-- 
6: Hello World my friend.
        Good morning
synchronizedSayHelloAndWait: <-- 
synchronizedSayHelloAndWait: ---> 
        Sleeping .... 
1: Hello World my friend.
        Good morning
synchronizedSayHelloAndWait: <-- 
synchronizedSayHelloAndWait: ---> 
        Sleeping .... 
        Good morning
synchronizedSayHelloAndWait: <-- 
synchronizedSayHelloAndWait: ---> 
        Sleeping .... 
        Good morning
synchronizedSayHelloAndWait: <-- 
synchronizedSayHelloAndWait: ---> 
        Sleeping .... 
7: Hello World my friend.
5: Hello World my friend.
3: Hello World my friend.
        Good morning
synchronizedSayHelloAndWait: <-- 
9: Hello World my friend.

16.22.  Thread Usage in RMI

16.23.  Multiple Servers

Client:

Src/16_M/Client.java


import java.rmi.*;

public class Client {
	public static void main(String args[] ) {
	String message = "";
	try {
		MyServer obj =
			 (MyServer)Naming.lookup("//yps:2001/Server1");
		message = obj.sayHello();
		System.out.println(message);


		obj = (MyServer)Naming.lookup("//yps:2001/Server2");
		message = obj.sayHello();
		System.out.println(message);

	} catch (Exception e) {
		System.out.println("Something went wrong: " +
		e.getMessage());
		e.printStackTrace();
	}
  }
}

Source Code: Src/16_M/Client.java

Server 1:

Src/16_M/Server1Impl.java


import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class Server1Impl
        extends UnicastRemoteObject
        implements MyServer
{
        private String name;

        public Server1Impl(String s) throws RemoteException {
                name = s;
        }

        public String sayHello() throws RemoteException {
                return  "Server1()";
        }

        public static void main(String args[])
        {
                // Create and install a security manager
                // System.setSecurityManager(new RMISecurityManager());

                try {
                        Server1Impl obj = new Server1Impl("Server1");
                        Naming.rebind("//yps:2001/Server1", obj);
                        System.out.println("Server1 bound in registry");
                } catch (Exception e) {
                        System.out.println("Server1Impl err: "
			   + e.getMessage());
                        e.printStackTrace();
                }
        }
}

Source Code: Src/16_M/Server1Impl.java

Server 2:

Src/16_M/Server2Impl.java


import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class Server2Impl
        extends UnicastRemoteObject
        implements MyServer
{
        private String name;

        public Server2Impl(String s) throws RemoteException {
                name = s;
        }

        public String sayHello() throws RemoteException {
                return  "Server2()";
        }

        public static void main(String args[])
        {
                // Create and install a security manager
                // System.setSecurityManager(new RMISecurityManager());

                try {
                        Server2Impl obj = new Server2Impl("Server2");
                        Naming.rebind("//yps:2001/Server2", obj);
                        System.out.println("Server2Server bound in registry");
                } catch (Exception e) {
                        System.out.println("Server2Impl err: "
			   + e.getMessage());
                        e.printStackTrace();
                }
        }
}

Source Code: Src/16_M/Server2Impl.java

% make
rmic Server1Impl
rmic Server2Impl
javac Client.java
rmiregistry 2001 &
sleep 1
java Server1Impl &
java Server2Impl &
sleep 4
Server2Server bound in registry
Server1 bound in registry
java Client
Server1()
Server2()

16.24.  Running Multiple Server on different Machines

--
boot time
--
via inetd
--
"by hand"

16.25.  Calculating PI

% make
javac Client.java
rmiregistry &
sleep 1
java PiServer &
sleep 4
        PiServer: PiServer()
PiServer bound in registry
java Client
3.1415926536
% java Client 100
3.141592653589793238462643383279502884197
16939937510582097494459230781640628620899
86280348253421170680
% 

Server Interface:

Src/16_M/MyServer.java


public interface MyServer extends java.rmi.Remote {
        String sayHello() throws java.rmi.RemoteException;
}

Source Code: Src/16_M/MyServer.java

Class java/gmath.BigDecimal

Immutable, arbitrary-precision signed decimal numbers. A BigDecimal consists of an arbitrary precision integer value and a non-negative integer scale, which represents the number of decimal digits to the right of the decimal point. (The number represented by the BigDecimal is intVal/7**scale.) BigDecimals provide operations for basic arithmetic, scale manipulation, comparison, format conversion and hashing. The compute engine, a remote object in the server, takes tasks from clients, runs them, and returns any results. The tasks are run on the machine where the server is running. This sort of distributed application could allow a number of client machines to make use of a particularly powerful machine or one that has specialized hardware.

Client:

Src/16_C/Client.java.minusSTART_STOP


import java.rmi.*;
import java.math.*;

public class Client {

    public static void doIt(String host, String port, int digits) {
	String message = "";
	try {
		MyServer obj = (MyServer)Naming.lookup("//" +
			host + ":" + port + "/PiServer");
		System.out.println(obj.computePi(digits));

	} catch (Exception e) {
		System.out.println("Something went wrong: " +
		e.getMessage());
		e.printStackTrace();
	}

   }

    public static void main(String args[] ) {
    int    digits = 10;
    String host   = "yps";
    String port   = "";


    if ( args.length  >= 1 )	{
	try {
		digits = Integer.parseInt(args[0]);
	}
	catch ( NumberFormatException e )	{
		System.out.println("Hm , digits = " + args[0]);
		System.exit(1);
	}

    }
    if ( args.length >= 2 )	{
	host = args[1];
    }

    if ( args.length  == 3 )	{
	try {
		port = args[2];
		Integer.parseInt(port);
	}
	catch ( NumberFormatException e )	{
		System.out.println("Port = " + port + " is not valid.");
		System.exit(1);
	}

    }
    if ( args.length  > 3 )	{
	System.out.println("Usage: java Client [digits [host [port]]]");
	System.exit(1);
    }
    doIt(host, port, digits);
  }
}

Source Code: Src/16_C/Client.java Interface:

Src/16_C/MyServer.java


import java.math.*;

public interface MyServer extends java.rmi.Remote {
        BigDecimal computePi(int digits)
        throws java.rmi.RemoteException;
}

Source Code: Src/16_C/MyServer.java

Server:

Src/16_C/PiServer.java.minusSTART_STOP


import java.rmi.*;
import java.math.*;
import java.rmi.server.UnicastRemoteObject;

public class PiServer
        extends UnicastRemoteObject
        implements MyServer
{
    /** constants used in pi computation */
    private static final BigDecimal ZERO = 
        BigDecimal.valueOf(0);
    private static final BigDecimal  ONE = 
        BigDecimal.valueOf(1);
    private static final BigDecimal FOUR = 
        BigDecimal.valueOf(4);

    /** rounding mode to use during pi computation */
    private static final int roundingMode = 
        BigDecimal.ROUND_HALF_EVEN;

    /** digits of precision after the decimal point */
    private int digits;
    

    /**
     * Construct a task to calculate pi to the specified
     * precision.
     */
    public PiServer() throws RemoteException {
        System.out.println("\tPiServer: PiServer()");
    }
    /**
     * Compute the value of pi to the specified number of 
     * digits after the decimal point.  The value is 
     * computed using Machin's formula:
     *
     *          pi/4 = 4*arctan(1/5) - arctan(1/239)
     *
     * and a power series expansion of arctan(x) to 
     * sufficient precision.
     */
    public BigDecimal computePi(int digits) throws RemoteException {
        int scale = digits + 5;
        BigDecimal arctan1_5 = arctan(5, scale);
        BigDecimal arctan1_239 = arctan(239, scale);
        BigDecimal pi = arctan1_5.multiply(FOUR).subtract(
                                  arctan1_239).multiply(FOUR);
        return pi.setScale(digits, 
                           BigDecimal.ROUND_HALF_UP);
    }
    /**
     * Compute the value, in radians, of the arctangent of 
     * the inverse of the supplied integer to the speficied
     * number of digits after the decimal point.  The value
     * is computed using the power series expansion for the
     * arc tangent:
     *
     * arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + 
     *     (x^9)/9 ...
     */   
    public static BigDecimal arctan(int inverseX, 
                                  int scale) 
    {
        BigDecimal result, numer, term;
        BigDecimal invX = BigDecimal.valueOf(inverseX);
        BigDecimal invX2 = 
            BigDecimal.valueOf(inverseX * inverseX);

        numer = ONE.divide(invX, scale, roundingMode);

        result = numer;
        int i = 1;
        do {
            numer = 
                numer.divide(invX2, scale, roundingMode);
            int denom = 2 * i + 1;
            term = 
                numer.divide(BigDecimal.valueOf(denom),
                             scale, roundingMode);
            if ((i % 2) != 0) {
                result = result.subtract(term);
            } else {
                result = result.add(term);
            }
            i++;
        } while (term.compareTo(ZERO) != 0);
        return result;
    }


        public static void main(String args[])
        {
                // Create and install a security manager
                // System.setSecurityManager(new RMISecurityManager());

                try {
                        PiServer obj = new PiServer();
                        Naming.rebind("//yps:2042/PiServer", obj);
                        System.out.println("PiServer bound in registry");
                } catch (Exception e) {
                        System.out.println("PiServer err: " + e.getMessage());
                        e.printStackTrace();
                }
        }
}

Source Code: Src/16_C/PiServer.java

An other Server (much worse in performance):

Src/16_C/PiServerLeibnitz.java.minusSTART_STOP


import java.rmi.*;
import java.math.*;
import java.rmi.server.UnicastRemoteObject;

public class PiServerLeibnitz
        extends UnicastRemoteObject
        implements MyServer
{
    /** constants used in pi computation */
    private static final BigDecimal ZERO = 
        BigDecimal.valueOf(0);
    private static final BigDecimal  ONE = 
        BigDecimal.valueOf(1);

    /** rounding mode to use during pi computation */
    private static final int roundingMode = 
        BigDecimal.ROUND_HALF_EVEN;

    /** digits of precision after the decimal point */
    private int digits;
    

    /**
     * Construct a task to calculate pi to the specified
     * precision.
     */
    public PiServerLeibnitz() throws RemoteException {
        System.out.println("\tPiServerLeibnitz: PiServerLeibnitz()");
    }
    /**
     * Compute the value of pi to the specified number of 
     * digits after the decimal point.  The value is 
     * computed using Leibnitz's formula (1674):
     *
     *          pi/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 ...
     *
     */
    public BigDecimal computePi(int digits) throws RemoteException {
        int scale = digits + 5;
        BigDecimal piD4 = calculateSum(5, scale);
        BigDecimal pi = piD4.multiply( new BigDecimal((float)4));

        return pi.setScale(digits, BigDecimal.ROUND_HALF_UP);
    }
    public static BigDecimal calculateSum(int inverseX, int scale) 
    {
        BigDecimal ONE    =  new BigDecimal((float)1.0);
        BigDecimal result =  new BigDecimal((float)1.0);
	BigDecimal term;

        int i = 3;
        do {
	    BigDecimal numer  =  new BigDecimal((float)i);
	    term = ONE.divide (numer, scale, roundingMode) ;
            result = result.subtract( term );

	    i += 2;
	    numer  =  new BigDecimal((float)i);
	    term = ONE.divide (numer, scale, roundingMode) ;
            result = result.add( term );
	    i += 2;

        } while (term.compareTo(ZERO) != 0);
        return result;
    }


        public static void main(String args[])
        {
                // Create and install a security manager
                // System.setSecurityManager(new RMISecurityManager());

                try {
                        PiServerLeibnitz obj = new PiServerLeibnitz();
                        Naming.rebind("//yps:2042/PiServer", obj);
                        System.out.println("PiServerLeibnitz bound in registry");
                } catch (Exception e) {
                        System.out.println("PiServerLeibnitz err: " + e.getMessage());
                        e.printStackTrace();
                }
        }
}

Source Code: Src/16_C/PiServerLeibnitz.java

16.26.  Receive and send Objects

Interface:

Src/16_Hash/HashTableInterface.java


import java.util.*;

public interface HashTableInterface extends java.rmi.Remote {
    Hashtable playWithAHashTable(String t)
		throws java.rmi.RemoteException;
}

Source Code: Src/16_Hash/HashTableInterface.java

Client:

Src/16_Hash/HashTableC.java.minusSTART_STOP


import java.rmi.*;
import java.util.*;

public class HashTableC {
	public static void main(String args[] ) {
	String plusMovie = "Smoke Signals";
	Hashtable aHashTable = new Hashtable();
	aHashTable.put("plusplus  Movie", "Comedian Harmonists");

	System.out.println("Client: aHashTable local = " +
			aHashTable.toString());
	try {

		HashTableInterface obj =
			 (HashTableInterface)Naming.lookup("//yps/HelloServer");

		aHashTable = obj.playWithAHashTable(plusMovie);

	} catch (Exception e) {
		System.out.println("HelloApplet exception: " +
		e.getMessage());
		e.printStackTrace();
	}
	System.out.println("Client: aHashTable remote = " +
			aHashTable.toString());
  }
}

Source Code: Src/16_Hash/HashTableC.java

Server:

Src/16_Hash/HashTableServer.java


import java.util.*;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class HashTableServer
        extends UnicastRemoteObject
        implements HashTableInterface {
        private String name;

        public HashTableServer(String s) throws RemoteException {
		System.out.println(
		   "\tHashTableServer: HashTableServer(String s)");
                name = s;
        }

        public Hashtable playWithAHashTable(String t)
		throws java.rmi.RemoteException {
		Hashtable aHashTable = new Hashtable();
		aHashTable.put("plusplus  Movie", t);
		System.out.println("\tserver: aHashTable = " +
			aHashTable.toString());
		t = "done";
		return aHashTable;
	}
        public static void main(String args[])
        {
                // System.setSecurityManager(new RMISecurityManager());

                try {
                    HashTableServer obj = new HashTableServer("HelloServer");
                    Naming.rebind("//yps/HelloServer", obj);
                    System.out.println("HelloServer bound in registry");
                } catch (Exception e) {
                    System.out.println("HashTableServer err: " + e.getMessage());
                    e.printStackTrace();
                }
        }
}

Source Code: Src/16_Hash/HashTableServer.java

Result:

% make
rmic HashTableServer
javac HashTableC.java
rmiregistry &
sleep 1
java HashTableServer &
sleep 4
        HashTableServer: HashTableServer(String s)
HelloServer bound in registry
java HashTableC
Client: aHashTable local = {plusplus  Movie=Comedian Harmonists}
        server: aHashTable = {plusplus  Movie=Smoke Signals}
Client: aHashTable remote = {plusplus  Movie=Smoke Signals}
killIt java
kill -9 27386
Killed
killIt 
kill -9 27366
kill -9 27374
# make clean 

16.27.  Dynamic Class Loading

RMI allows parameters, return values and exceptions passed in RMI calls to be any object that is serializable. RMI uses the object serialization mechanism to transmit data from one virtual machine to another and also annotates the call stream with the appropriate location information so that the class definition files can be loaded at the receiver.

When parameters and return values for a remote method invocation are unmarshalled to become live objects in the receiving VM, class definitions are required for all of the types of objects in the stream. The unmarshalling process first attempts to resolve classes by name in its local class loading context (the context class loader of the current thread). RMI also provides a facility for dynamically loading the class definitions for the actual types of objects passed as parameters and return values for remote method invocations from network locations specified by the transmitting endpoint. This includes the dynamic downloading of remote stub classes corresponding to particular remote object implementation classes (and used to contain remote references) as well as any other type that is passed by value in RMI calls, such as the subclass of a declared parameter type, that is not already available in the class loading context of the unmarshalling side.

To support dynamic class loading, the RMI runtime uses special subclasses of java/gio.ObjectOutputStream and java/gio.ObjectInputStream for the marshal streams that it uses for marshalling and unmarshalling RMI parameters and return values.


Weiter | Weiter | Weiter | Weiter | Kommentar


Created by unroff, java2html & & hp-tools. © by csfac. All Rights Reserved (2001).
It is not allowed to print these pages on a CAST printer.
Last modified 09/May/01