|
|
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.
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.
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.
TCP is using protocl port numbers to indentify the ultimate destination.
How does one deteremine the port to communicate with?
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
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.
Host info
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
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
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 %
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:
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
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">
import java.net.*;
import java.io.*;
import java.util.*;
public class MTS extends Thread {
ServerSocket listen;
static String hostName = "yps";
int port = 4242;
public MTS() {
listen = null;
}
public MTS(int port) {
try {
listen = new ServerSocket(port);
System.out.println ("Listening on port: "
+ getLocalPort());
} catch(Exception e) {
System.out.println(e);
}
}
public int getLocalPort () {
return listen.getLocalPort();
}
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 MTS(port).listenToPort();
}
}
}
public void run() {
try {
Socket clnt = listen.accept();
System.out.println(clnt.toString());
PrintWriter out = new PrintWriter
(clnt.getOutputStream (), true);
out.println("It is now: " + new Date());
listen.close();
} catch(Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
public void listenToPort() {
try {
for(;;) {
Socket clnt = listen.accept();
int newSocket;
System.out.println("Somebody connected ... ");
MTS aServer = new MTS(0);
aServer.start();
System.out.println("offer ... " +
aServer.getLocalPort());
PrintWriter out = new PrintWriter
(clnt.getOutputStream (), true);
out.println(aServer.getLocalPort());
// clnt.close();
}
} catch(Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
public static void main(String argv[]) {
if ( argv.length == 0 )
new MTS(0).listenToPort();
else
new MTS().parseArgs(argv);
}
}
Source Code: Src/16/MTS.java
import java.net.*;
import java.io.*;
import java.util.*;
public class MTSclient {
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 {
Socket socket = new Socket(hostName, port);
BufferedReader din = new BufferedReader (
new InputStreamReader (socket.getInputStream()));
String newPort = din.readLine ();
System.out.println ("Use from now in port: " + newPort);
socket.close();
din.close();
socket = new Socket(hostName,
new Integer(newPort).intValue());
din = new BufferedReader (
new InputStreamReader (socket.getInputStream()));
System.out.println("got: " + din.readLine () );
} catch (Exception e) {
System.out.println (e);
}
}
public static void main(String argv[]) {
MTSclient aMTSclient = new MTSclient();
aMTSclient.parseArgs(argv);
aMTSclient.doTheJob();
}
}
Source Code: Src/16/MTSclient.java
# Window 1: % java MTS Listening on port: 38834 Somebody connected ... Listening on port: 38836 offer ... 38836 Socket[addr=yps/129.21.38.198,port=38837,localport=38836] Somebody connected ... Listening on port: 38839 offer ... 38839 Socket[addr=yps/129.21.38.198,port=38840,localport=38839] Somebody connected ... Listening on port: 38842 offer ... 38842 Socket[addr=yps/129.21.38.198,port=38843,localport=38842] # Window 2: % java MTSclient -port 38834 Use from now in port: 38836 got: It is now: Mon Apr 30 15:26:53 EDT 2001 % java MTSclient -port 38834 java MTSclient -port 38834 Use from now in port: 38839 got: It is now: Mon Apr 30 15:27:02 EDT 2001 % java MTSclient -port 38834 java MTSclient -port 38834 Use from now in port: 38842 got: It is now: Mon Apr 30 15:27:07 EDT 2001
An example:
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
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
# Window 1: % java DayTimeUDPServer -port 53818 Listening on port: 53818 Sending to port: 53840 Sending data: es schlaegt: Mon Apr 30 15:27:19 EDT 2001 # Window 2: % java DayTimeUDP -port 53818 host: yps port: 53818 after creation received: -es schlaegt: Mon Apr 30 15:27:25 EDT 2001
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.
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.
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
See also http://java.sun.com/products/jdk/1.2/docs/guide/rmi/spec/rmiTOC.doc.html
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.
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.
Starting the application includes running the RMI remote object registry, the server, and the client.
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.
The Client:
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:
public interface Hello extends java.rmi.Remote {
String sayHello() throws java.rmi.RemoteException;
}
Source Code: Src/16_D/Hello.java
The Server:
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
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.
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.
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);
The Client:
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:
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:
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
Server:
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:
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.
Client:
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:
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:
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()
run `ssh-keygen -P`
this will generate a public / private keypair that does not require a password. (for our example, we will assume that the files created are id_dsa_1024_c and id_dsa_1024_c.pub)
*: [other keys] Key id_dsa_1024_c.pub
and the file ~/.ssh2/identification
*: [Other IdKeys] IdKey id_dsa_1024_c • Now... you can do this: ssh machine_name who and you will get the result from `who` without needing a .rhosts file
% 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:
public interface MyServer extends java.rmi.Remote {
String sayHello() throws java.rmi.RemoteException;
}
Source Code: Src/16_M/MyServer.java
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:
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:
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:
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):
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
Interface:
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:
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:
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
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.
|
|