RMI – Client and run the Library

This is the last part in the build up to the RMI (Remote Method Invocation) this is the clients part, the previous part was the RMI library / server. Where the server will listen for a clients request.

So to start with we need to be able to call the remote server, so we need to be able to have permission from the RMI java security package.

System.setSecurityManager(new RMISecurityManager());

next we need to build up the RMI server request URL (where the server is and also the remote class that it is listening on and as taken from here we are listening on the “RemoteBook” class) (we are listening on the localhost as the server)

String remoteClass = "RemoteBook";
String rmiURL = "rmi://localhost/" + remoteClass;

since all the client needs to know is what interface has been implemented within the server (the borrowable interface) then we just need to create a new object based on that that then links to the servers listening class rmiURL (as taken from above)

Borrowable remoteBook = (Borrowable)Naming.lookup(rmiURL);

and then just call the functions that will have been implemented on the server (the server has used the Book.java which implements the Borrowable interface) because now they are linked.

The java Naming object is a RMI object that allows for the server to bind’s its class object to a URL and the client to link its interface object to the servers class object basically.

here is the client code in full

import java.util.*;
import java.rmi.*;
 
public class RMIClient {
	String remoteClass = "RemoteBook";
	String libraryCardNumber = "genuxCard";
 
	public RMIClient()
	{
		if (System.getSecurityManager()== null)
			System.setSecurityManager(new RMISecurityManager());
 
	}
 
	public boolean useLibrary()
	{
		boolean result = true;
		try {
			String rmiURL = "rmi://localhost/" + remoteClass;
			Borrowable remoteBook = (Borrowable)Naming.lookup(rmiURL);
			System.out.println("The book is checked out "+remoteBook.isCheckedOut());
 
			boolean outResult = remoteBook.checkOut(libraryCardNumber,new Date());
 
			if (outResult==true)
				System.out.println("Book checked out successfully");
			else
				result = false;
 
			if (remoteBook.isCheckedOut())
			{
				System.out.println("libraray Card number that has checked out the book is :"+remoteBook.checkedOutCardNumber());
			}
 
			boolean inResult = remoteBook.checkIn(libraryCardNumber, new Date());
 
			if (inResult==true)
				System.out.println("Book checked in");
			else
				result = false;
		}
		catch (Exception e)
		{
			System.out.println("RMI Error: "+e.getMessage());
			result = false;
		}
		return result;
	}
 
	public static void main(String[] args) {
		RMIClient RMIC = new RMIClient();
		boolean result = RMIC.useLibrary();
		if (result == false)
			System.out.println("Error using library");
 
	}
 
}

and if you save that as RMIClient.java, compile up the java files to create the class files

This is the policy file, if you save this as RMIpolicyfile.policy, it basically allows all permissions within the java security object, not the best security for servers but this will server as a local host test. (alter the where/your/class/files/are to where you are building up the java files into there class files, within eclipse it has a /src directory and a /bin so you would link to the /bin directory)

grant codeBase "file:/where/your/class/files/are" {
    permission java.security.AllPermission;
};

and now that you have the RMI server (RMIFactory) and the RMI client (RMIClient) all we need to do is to register the java RMI to allow connections on the linux command line I do

rmiregistry &

the “&” allows it to run in the back ground, then to run the server

java -Djava.security.policy=RMIpolicyfile.policy RMIFactory &
console output : Remote book object has been started

which this uses the security policy file from above and also runs again in the background (“&”) and now to just run the client

java -Djava.security.policy=RMIpolicyfile.policy RMIClient

once again since the client is requesting the RMI security, you need to tell it to use the RMI policy file from above, and the output would be

The book is checked out false
Book checked out successfully
libraray Card number that has checked out the book is :genuxCard Date taken out on Thu Apr 08 11:49:36 BST 2010
Book checked in

RMI – the Library factory

Now we have the library book, we can now build up the RMI library factory that will be the server for the clients to communicate to.

To start with we have to setup the security settings

System.setSecurityManager(new RMISecurityManager());

this is because the RMI library factory needs to “listen” on the server to remote clients to connect and due to the Java sandbox we have to make a request to the security manager to be allowed to “listen” for remote clients, without the permission there will be a error.

Remote error :Connection refused to host: 127.0.1.1; nested exception is: 
        java.net.ConnectException: Connection refused

I shall include the policy file when it comes to running the server/client setup.

now all we need to do is to bind the Book class RMI server and call it the “RemoteBook”, you need this to call with the client because you are basically allowing the server to communicate with the client to the Book that has been created (new Book(“Genuxs book… ) )

Book remoteBook = new Book("Genuxs book to borrow");
Naming.rebind("RemoteBook",remoteBook);

here is the full RMI Factory code

import java.rmi.*;
import java.rmi.server.*;
import java.net.*;
 
public class RMIFactory {
 
	public RMIFactory()
	{
		System.setSecurityManager(new RMISecurityManager());
	}
 
	public void createRemoteBook()
	{
		try {
			Book remoteBook = new Book("Genuxs book to borrow");
			Naming.rebind("RemoteBook",remoteBook);
 
		} 
		catch (RemoteException e)
		{
			System.out.println("Remote error :"+ e.getMessage());
		}
		catch (MalformedURLException mue)
		{
			System.out.println("Remote malformed error :"+mue.getMessage());
		}
 
		System.out.println("Remote book object has been started");
	}
 
	public static void main(String[] args) {
		RMIFactory RMIF = new RMIFactory();
		RMIF.createRemoteBook();
	}
 
}

if you save that as RMIFactory.java and next it is the client and running the RMI server and RMI client.

RMI – implementation of the library book

As from previous post, the Borrowable interface, for the RMI (Remote Method Invocation), this is the part of the Book class, this is what is called from the Library as such to see if a book has been taken out or not.

import java.util.*;
import java.rmi.*;
import java.rmi.server.*;
 
// UnicaseRemoteObject = remote object classes need to implement the related
// remote interface
public class Book extends UnicastRemoteObject implements Borrowable {
	private Date borrowDate;
	private Date returnDate;
	private String borrowerID;
	private String title;
	private boolean checkedOut = false;
 
	// create book.
	public Book (String bookName) throws RemoteException
	{
		title = bookName;
	}
 
	// is the book already checked out ?
	public boolean isCheckedOut() throws RemoteException
	{
		return checkedOut;
	}
 
	// if the book is checked out, return the library card number + date it was taken out on
	public String checkedOutCardNumber() throws RemoteException
	{
		String returnID = null;
		if (isCheckedOut())
		{
			returnID = borrowerID + " Date taken out on "+ borrowDate.toString();
		}
		return returnID;
	}
 
	public boolean checkOut(String cardNumber, Date d ) throws RemoteException
	{
		// do not check out the book if already checked out!
		if (isCheckedOut())
			return false;
		borrowerID = cardNumber;
		borrowDate = d;
		checkedOut = true;
		return true;
	}
 
	public boolean checkIn(String cardNumber, Date d) throws RemoteException
	{
		// if it is checked out, check the book in.
		if (isCheckedOut())
		{
			borrowerID = cardNumber;
			returnDate = d;
			checkedOut = false;
			return true;
		}
		return false;
	}
}

if you save that as Book.java, next comes the fun part the actual Library server as such.

RMI – interface

Sometimes you will want to call a remote server e.g. like in a library, and see if a book has been taken out or not. Well in Java you can use something that is called a Remote Method Invocation ( it is very similar to web services ) this allows for a server to respond to clients without sending any more data across than what is required.

In this part of the tutorial I am building up the interface which the Client can use because the server will be implementing the functions below, but the Client only needs to know what functions have been implemented.

import java.rmi.*;
import java.util.*;
 
// this is used by the RMIClient.java to communicate with the remote server
// the Book.java uses this to implement a Book
 
// a remote interface java.rmi.Remote 
public interface Borrowable extends Remote {
	// all interface functions must throw RemoteException
	// is the booked checked out
	public boolean isCheckedOut() throws RemoteException;
	// return the library card number
	public String checkedOutCardNumber() throws RemoteException;
	// check out the book
	public boolean checkOut(String cardNumber, Date d) throws RemoteException;
	// check back in the book
	public boolean checkIn(String cardNumber, Date d) throws RemoteException;
}

so if you save that as the Borrowable.java file.

Next I am going to do the Book.java file, which is what the server will use as the library book as such.

UDP Server

As from the UDP Client here is the UDP Server, it is similar to the TCP Server in that it makes connections with a remote client and sends and receives data, but once again this data is not checked to make sure that it has been received (the “fire and forget” setup again)

So to start with we need to create a server socket for the clients to connect to

DatagramSocket theSocket = new DatagramSocket(9999);

since we now have a place for the client to connect to we now need to wait for a client connection request

// create a place for the client to send data too
theRecievedPacket = new DatagramPacket(inBuffer, inBuffer.length);
// wait for a client to request a connection
theSocket.receive(theRecievedPacket);

once a client has requested some data, we can start the process of setting up the response, the response starts of with getting there details, there IP address and also the port number that they wish to talk on ( image attached below of the wireshark request and different port number)

// get the client details
clientAddress = theRecievedPacket.getAddress();
clientPort = theRecievedPacket.getPort();

and then just build up the response to send back and send it

String message = "Server - client sent : " + new String(theRecievedPacket.getData(),0, theRecievedPacket.getLength());
outBuffer = message.getBytes();
 
// send some data to the client
theSendPacket = new DatagramPacket(outBuffer, outBuffer.length, clientAddress, clientPort);
theSocket.send(theSendPacket);

here is the full java code

import java.io.*;
import java.net.*;
 
public class UDPServer {
 
	DatagramSocket theSocket = null;
	int serverPort = 9999;
 
	public UDPServer()
	{
		try {
			// create the server UDP end point
			theSocket = new DatagramSocket(serverPort);
 
			System.out.println("UDP Socket (end point) created");
		} catch (SocketException ExceSocket)
		{
			System.out.println("Socket creation error : "+ ExceSocket.getMessage());
		}
	}
 
	public void clientRequest()
	{
		DatagramPacket theRecievedPacket;
		DatagramPacket theSendPacket;
		InetAddress clientAddress;
		int clientPort;
		byte[] outBuffer;
		byte[] inBuffer;
 
		// create some space for the text to send and recieve data 
		outBuffer = new byte[500];
		inBuffer = new byte[50];
 
		try {
			// create a place for the client to send data too
			theRecievedPacket = new DatagramPacket(inBuffer, inBuffer.length);
			// wait for a client to request a connection
			theSocket.receive(theRecievedPacket);
			System.out.println("Client connected");
 
			// get the client details
			clientAddress = theRecievedPacket.getAddress();
			clientPort = theRecievedPacket.getPort();
 
			String message = "Server - client sent : " + new String(theRecievedPacket.getData(),0, theRecievedPacket.getLength());
			outBuffer = message.getBytes();
 
			System.out.println("Client data sent ("+message+")");
			// send some data to the client
			theSendPacket = new DatagramPacket(outBuffer, outBuffer.length, clientAddress, clientPort);
			theSocket.send(theSendPacket);
 
		} catch (IOException ExceIO)
		{
			System.out.println("Error with client request : "+ExceIO.getMessage());
		}
		// close the server socket
		theSocket.close();
	}
 
	public static void main(String[] args)
	{
		UDPServer theServer = new UDPServer();
		theServer.clientRequest();
	}
}

if you save that as UDPServer.java and then compile and run

javac UDPServer.java

and then run the java UDPserver program, I have inserted the “— waiting for the client to connect” line because that is where the server will stop waiting, once the client as connected the rest of the output will be outputted.

java UDPServer 
UDP Socket (end point) created
---- waiting for the client to connect
Client connected
Client data sent (Server - client sent : genux)

and then run the UDPClient to connect to the server

java UDPClient 
Client socket created
Message sending is : genux
Client - server response : Server - client sent : genux

Here is the image of a wireshark connection request over the UDP and with the clients port request number.

Request port number
Request port number

UDP Client

A UDP Client is very similar to a TCP Client in that it communicates with a server, but the main difference between the two is that UDP is more of a “fire and forget” setup than lets make sure that the data is sent across. A good example of this would be for a UDP server/client to be something like a radio station, when you are listening to the radio and if you miss part of the song then it does not really matter (apart from if you was singing along!!), but with TCP server/client you want to have all of the data associated with that file.

// create a socket to connect to the server with
DatagramSocket theSocket = new DatagramSocket();
int serverPort = 9999;
// the remote server, in this case I am using the local host but you could use any remote server as long as the UDP server is running on it
InetAddress theServer = InetAddress.getLocalHost();
// and connect the socket to the remote server and port number
theSocket.connect(theServer,serverPort);

and now we build up a message to send to the server, we are using bytes because that is what is sent over with the DatagramPacket’s (these are the packets of data within the wrapped up “letter” that is being sent from the client to the server, the “letter” in this case is the details included within the packet e.g. address to, address from more details are here)

byte[] outBuffer = new byte[50];
String message = "genux";
outBuffer = message.getBytes();

and then to send the information to the server we, since theSocket is already connected to the server then do not need to tell the DatagramPacket where to send.

// build up a packet to send to the server
theSendPacket = new DatagramPacket(outBuffer, outBuffer.length);
// send the data
theSocket.send(theSendPacket);

and now to get a response (if the server gets, and the client does receive one)

// get the servers response within this packet
theReceivedPacket = new DatagramPacket(inBuffer, inBuffer.length);
theSocket.receive(theReceivedPacket);
 
// the server response is...
System.out.println("Client - server response : "+new String(theReceivedPacket.getData(), 0, theReceivedPacket.getLength()));

here is the full code

import java.io.*;
import java.net.*;
 
public class UDPClient {
 
	DatagramSocket theSocket = null;
	int serverPort = 9999;
 
	public UDPClient()
	{
		try {
			theSocket = new DatagramSocket();
 
			// but if you want to connect to your remote server, then alter the theServer address below
			InetAddress theServer = InetAddress.getLocalHost();
			theSocket.connect(theServer,serverPort);
 
			System.out.println("Client socket created");
		}catch (SocketException ExceSocket)
		{
			System.out.println("Socket creation error  : "+ExceSocket.getMessage());
		} 
		catch (UnknownHostException ExceHost)
		{
			System.out.println("Socket host unknown : "+ExceHost.getMessage());
		}
	}
 
	public void connectToServer()
	{
		DatagramPacket theSendPacket;
		DatagramPacket theReceivedPacket;
		InetAddress theServerAddress;
		byte[] outBuffer;
		byte[] inBuffer;
 
		// the place to store the sending and receiving data
		inBuffer = new byte[500];
		outBuffer = new byte[50];
		try {
			String message = "genux";
			outBuffer = message.getBytes();
 
			System.out.println("Message sending is : " + message);
 
			// the server details
			theServerAddress = theSocket.getLocalAddress();
 
			// build up a packet to send to the server
			theSendPacket = new DatagramPacket(outBuffer, outBuffer.length, theServerAddress, serverPort);
			// send the data
			theSocket.send(theSendPacket);
 
			// get the servers response within this packet
			theReceivedPacket = new DatagramPacket(inBuffer, inBuffer.length);
			theSocket.receive(theReceivedPacket);
 
			// the server response is...
			System.out.println("Client - server response : "+new String(theReceivedPacket.getData(), 0, theReceivedPacket.getLength()));
			theSocket.close();
		} catch (IOException ExceIO)
		{
			System.out.println("Client getting data error : "+ExceIO.getMessage());
		}
	}
 
	public static void main(String[] args)
	{
		UDPClient theClient = new UDPClient();
		theClient.connectToServer();
	}
}

if you save that as UDPClient.java and then to compile

javac UDPClient.java

the server is the next part of the puzzle, which is coming next.

TCP Client

As from the TCP Server, this is the client that will connect to the server and output the response from the server.

Since we are the client, we need to know where the server is to connect to, other wise we would not connect to anywhere!!!.. since within this tutorial I am using the local host for running the server as well (you could alter this to where you want to run the server on)

InetAddress theHost = InetAddress.getLocalHost();
// get the local hostname as well
String theHostName = theHost.getHostName();

and with this information you can create a new Socket to connect to the server on the port 9999 (which is the same port number that the server is listening on)

// open the socket connection with the server on port 9999
Socket theSocket = new Socket(theHostName, 9999);

to gain the server data, I am using the ObjectInputStream, with passing the socket from above connection to the server, then just read a line from the ObjectInputStream into a String local variable.

ObjectInputStream ois = new ObjectInputStream(theSocket.getInputStream());
String response = (String)ois.readLine();
// just output the response.
System.out.println("Response was : "+response);

and that is it, all very simple since most of the “interesting” stuff over the networking connections happening under the hood of java, which is just great.

Here is the full source code.

import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
 
public class TCPClient {
	InetAddress theHost;
	Socket theSocket;
	int port = 9999;
 
	public TCPClient() {
		try {
			// the local host IP address - where you want to connect to.. 
			theHost = InetAddress.getLocalHost();
			// get the local hostname as well
			String theHostName = theHost.getHostName();
			// open the socket connection with the server on port 9999
			theSocket = new Socket(theHostName, port);
 
			System.out.println("Server connection opened, going to listen");		
 
			ObjectInputStream ois = new ObjectInputStream(theSocket.getInputStream());
			String response = (String)ois.readLine();
 
			System.out.println("Response was : "+response);
			theSocket.close();
		} catch (UnknownHostException ExecHost)
		{
			System.out.println("Unknown Host Error");
		}
		catch (IOException ExceIO)
		{
			System.out.println("Error creatin socket : "+ExceIO.getMessage());
		}
	}
 
	public static void main(String[] args) {
		new TCPClient();
	}
 
 
}

If you save as TCPClient.java and then to compile and run (of course you need to be running in another console the TCPServer since the client will have nothing to connect to !!!)

javac TCPClient.java
java TCPClient

and the output would be

Server connection opened, going to listen
Response was : Hi from the server

you could use wireshark to watch what is happening.