Networking in Java
Networking in Java
Sockets
   Computers running on the Internet communicate with each other using
    either the Transmission Control Protocol (TCP) or the User Datagram
    Protocol (UDP).
   When you write Java programs that communicate over the network, you
    are programming at the application layer.
   Typically, you don't need to concern yourself with the TCP and UDP
    layers.
   Instead, you can use the classes in the java.net package.
   These classes provide system-independent network communication.
   However, to decide which Java classes your programs should use, you do
    need to understand how TCP and UDP differ.
    Sockets…
   TCP is a connection-based protocol that provides a reliable flow of data
    between two computers.
   When two applications want to communicate to each other reliably, they
    establish a connection and send data back and forth over that connection.
   TCP guarantees that data sent from one end of the connection actually gets
    to the other end and in the same order it was sent.
   Otherwise, an error is reported.
   HTTP, FTP, and Telnet are all examples of applications that require a
    reliable communication channel.
   UDP is a protocol that sends independent packets of data, called
    datagrams, with no guarantees about arrival.
   UDP is not connection-based unlike TCP.
   For many applications, the guarantee of reliability is critical to the success
    of the transfer of information from one end of the connection to the other.
    Sockets…
   However, other forms of communication don't require such strict standards.
   In fact, they may be slowed down by the extra overhead or the reliable
    connection may invalidate the service altogether.
Ports
   Generally speaking, a computer has a single physical connection to the
    network.
   All data destined for a particular computer arrives through that connection.
   However, the data may be intended for different applications/servers
    running on the computer.
   So how does the computer know to which application to forward the data?
   Through the use of ports.
   Data transmitted over the Internet is accompanied by addressing
    information that identifies the computer and the port for which it is
    Sockets…
   The computer is identified by its 32-bit IP address, which IP uses to deliver
    data to the right computer on the network.
   Ports are identified by a 16-bit number, which TCP and UDP use to deliver
    the data to the right application.
boolean isBound()                It returns the binding state of the ServerSocket. It returns true if the
                                 ServerSocket has ever been bound to a port.
                                 It listens for a connection to be made to this socket and accepts it. The
Socket accept()                  method blocks until a connection is made. It throws IOException if an
                                 I/O error occurs when waiting for a connection.
boolean isClosed()               Returns the closed state of the ServerSocket. It returns true if the socket
                                 has been closed.
                                 Closes this server socket. Any thread currently blocked in
void close()                     ServerSocket.accept() will throw a SocketException. It throws
                                 IOException if an I/O error occurs when closing the socket.
                                 Sets the default receive buffer size for sockets accepted by the server
setReceiveBufferSize(int size)   socket. This controls the suggested send buffer size used for
                                 network input.
int getReceiveBufferSize()       Returns the value of the buffer size that will be used for Sockets
                                 accepted from this ServerSocket.
    TCP Server Sockets…
   Example: creating a server that listens for clients on port 4444
    ServerSocket servSocket;
    try {
       servSocket = new ServerSocket(4444);
    } catch (IOException e) {
       System.out.println("Could not listen on port: 4444");
       System.exit(-1);
    }
   ServerSocket provides a system-independent implementation of the server
    side of a client-server socket connection.
   The constructor for ServerSocket throws an exception if it can't listen on
    the specified port (for example, the port is already being used).
   If the server successfully binds to its port, then the ServerSocket object is
    successfully created and the server continues to accept a connection from a
   ServerSocket has a method called accept(), which is a blocking call that will
    wait for a client to initiate connections
   It then return a normal Socket that is then used for communication with the
    client.
   The accept() method returns a Socket object connecting the client and the
    server.
   Example: accepting client request on the server after creating the listener
    ServerSocket servSocket ;
    Socket socket = null;
    try {
       servSocket = new ServerSocket(4444);
    } catch (IOException e) {
       System.out.println("Could not listen on port: 4444");
       System.exit(-1);
    }
    try {
       socket = servSocket.accept();
    } catch (IOException e) {
       System.out.println("Accept failed: 4444");
       System.exit(-1);
    TCP Server Sockets…
   Server manages each client connection with a Socket object.
   After binding the server to a port with a ServerSocket, the server listens
    indefinitely (or blocks) for an attempt by a client to connect.
   To listen for a client, the program calls accept() method of ServerSocket as
    in
          Socket connection = server.accept();
   This statement returns a Socket object when a connection with a client is
    established.
    TCP Server Sockets…
   If you’re finished with a server socket, you should close it, especially if the
    program is going to continue to run for some time.
   This frees up the port and other programs may use it if necessary.
   Closing a ServerSocket should not be confused with closing a Socket.
   Closing a ServerSocket frees a port on the local host and it also breaks all
    currently open sockets that the ServerSocket has accepted.
   Server sockets are closed automatically when a program dies, so it’s not
    absolutely necessary to close them.
   Nonetheless, it is a good practice to close the socket before the program
    ends.
   Programmers often follow the approach “close if-not-null” in finally block.
 TCP Server Sockets…
Example: closing ServerSocket
ServerSocket server = null;
try {
  server = new ServerSocket(port);
  //work with the server socket
} finally {
  if (server != null) {
        try {
            server.close();
        } catch (IOException ex) {
            //ignore
        }
  }
    Client Connection
   A socket is a connection between two hosts.
   The Socket class is Java’s fundamental class for performing client-side TCP
    operations.
   Other client-oriented classes that make TCP network connections such as URL,
    URLConnection, HttpURLConnection, Applet, and JEditorPane all ultimately end
    up invoking the methods of this class.
   The Socket class itself uses native code to communicate with the local TCP stack of
    the host operating system.
   Socket can perform four basic operations: connect to a remote machine, send data,
    receive data, and close a connection.
   Java programs normally use client sockets in the following fashion:
      the program creates a new socket using a constructor
 Once connection established, the local and remote hosts get input and output
       streams from the socket and use those streams to send data to each other.
   The connection established by Socket is full-duplex where both hosts can send and
    receive data simultaneously.
    Client Connection…
   The Socket class constructor specifies the host and the port to connect to.
   Hosts may be specified as an InetAddress or a String.
   Remote ports are specified as int values from 1 to 65535:
        Socket(String host, int port) throws UnknownHostException, IOException
        Socket(InetAddress host, int port) throws IOException
   These constructors connect the server socket i.e. an active network connection is
    established to the remote host.
   If the connection can’t be opened for some reason, the constructor throws an
    IOException or an UnknownHostException.
   Example: client connection to a server
        try {
            Socket ss = new Socket("10.140.150.20", 80);
            // send and receive data...
        } catch (UnknownHostException ex) {
            System.err.println(ex);
    Client Connection…
   Once Socket is created, it is possible to start sending and receiving data
    after that.
   If the socket cannot be opened for some reason, the constructor throws an
    IOException.
   There are many reasons a connection attempt might fail: the host you’re
    trying to reach may not accept connections on that port, or routing
    problems may be preventing your packets from reaching their destination.
   Because this constructor doesn’t just create a Socket object but also tries to
    connect the socket to the remote host, you can use the object to determine
    whether connections to a particular port are allowed.
   Using this, you can write a port scanner that checks which ports are
    occupied and which ports are available.
Method                            Description
                                  It returns an input stream for reading bytes from this socket. IOException - if an I/O
InputStream getInputStream()      error occurs when creating the input stream, the socket is closed, the socket is not
                                  connected, or the socket input has been shutdown.
                               It returns an output stream for writing bytes to this socket. It throws IOException if
OutputStream getOutputStream() an I/O error occurs when creating the output stream or if the socket is not
                               connected.
                               Returns the connection state of the socket. Returns true if the socket was
boolean isConnected()
                               successfully connected to a server
                                  Closes this socket. Any thread currently blocked in an I/O operation upon this socket
void close()
                                  will throw a SocketException.
boolean isClosed()                Returns the closed state of the socket. Returns true if the socket has been closed.
                                  Returns whether the read-half of the socket connection is closed. Returns true if the
boolean isInputShutdown()
                                  input of the socket has been shutdown.
                                  Returns whether the write-half of the socket connection is closed. Returns true if the
boolean isOutputShutdown()
                                  output of the socket has been shutdown.
int getPort()                     Returns the remote port number to which this socket is connected.
int getLocalPort()                Returns the local port number to which this socket is bound.
                                  It returns the remote IP address to which this socket is connected, or null if the
InetAddress getInetAddress()
                                  socket is not connected.
InetAddress getLocalAddress()     Gets the local address to which the socket is bound.
                                  The method suggests a number of bytes to use for buffering output on this socket.
setSendBufferSize(int size)
                                  The OS is free to ignore this suggestion.
int getSendBufferSize()           Returns the value of the buffer size used by the platform for output on this Socket.
                                  The method suggests a number of bytes to use for buffering input from this socket.
setReceiveBufferSize(int size)
                                  However, the underlying implementation is free to ignore this suggestion.
int getreceiveBufferSize()        It returns the actual size of the receive buffer.
private ServerSocket serverSocket;
                                                          Example: server side that waits     for clients to
public ServerListening() {
                                                          connect to it
   try {
      serverSocket = new ServerSocket(110);
      startServer();
   } catch (IOException ex) {
      System.out.println(ex.getMessage());
   }
}
public void startServer() {
   System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
   while (true) {
      try {
         Socket socket = serverSocket.accept();
         System.out.println("Just connected to " + socket.getRemoteSocketAddress());
         DataInputStream in = new DataInputStream(socket.getInputStream());
         System.out.println(in.readUTF());
         DataOutputStream out = new DataOutputStream(socket.getOutputStream());
         out.writeUTF("Thank you for connecting to " + socket.getLocalSocketAddress());
         out.writeUTF("\nGoodbye!");
         socket.close();
      }catch (IOException e) {
         e.printStackTrace(); break;
      }
Example: a client program that connects to a server by using a socket and sends a
greeting, and then waits for a response.
public class ClientConnection {
  public static void main(String[] args) {
     String serverName = "10.120.130.140";
     int port = 110;
     try {
        System.out.println("Connecting to " + serverName + " on port " + port);
        Socket client = new Socket(serverName, port);
        System.out.println("Just connected to " + client.getRemoteSocketAddress());
        OutputStream outToServer = client.getOutputStream();
        DataOutputStream out = new DataOutputStream(outToServer);
        out.writeUTF("Hello from client");
   To see the local port on the client, you can write the following code on the
    client side
    System.out.println("local port: " + socket.getLocalPort());
    Client Connection…
   The close() method shuts down both input and output from the socket by
    closing the socket.
   On occasion, you may want to shut down only half of the connection,
    either input or output.
   The shutdownInput() and shutdownOutput() methods close only half the
    connection:
          void shutdownInput()
          void shutdownOutput()
   Neither actually closes the socket.
   Instead, they adjust the stream connected to the socket so that it thinks it’s
    at the end of the stream.
   Further reads from the input stream after shutting down input return –1.
   Further writes to the socket after shutting down output throw an
    IOException.
 Client Connection…
Reading from and Writing to Sockets
 After the server accepts the connection and Socket is created, communication
  sockets.
 To get an input stream, use the getInputStream() method on a socket object.
  object.
 For example, the following statements create an InputStream stream and an
 Typically, a server runs continuously on a server computer, and clients from all
                  outputToClient.writeDouble(area);
                  jta.append("Radius received from client: " + radius + '\n');
                  jta.append("Area computed: " + area + '\n');
              }
          } catch (IOException ex) {
              ex.printStackTrace();
          }
      }
  }
    2.2 UDP Datagrams
   Some applications that you write to communicate over the network will not
    require the reliable, point-to-point channel provided by TCP.
   Rather, your applications might benefit from a mode of communication that
    delivers independent packages of information whose arrival and order of
    arrival are not guaranteed.
   The UDP protocol provides a mode of network communication whereby
    applications send packets of data, called datagrams, to one another.
   Datagrams are bundles of information passed between machines.
   A datagram is an independent, self-contained message sent over the
    network whose arrival, arrival time, and content are not guaranteed.
   Once the datagram has been released to its intended target, there is no
    assurance that it will arrive at the destination.
   Likewise, when the datagram is received, there is no assurance that it
    hasn’t been damaged in transit or that whoever sent it is still there to
    receive a response.
    UDP Datagrams…
   UDP is appropriate for data transfers where it doesn't matter if a packet is
    lost in transition.
   For instance, imagine a transfer of a live TV-signal over the internet.
   You want the signal to arrive at the clients as close to live as possible.
   Therefore, if a frame or two are lost, you don't really care.
   You don't want the live broadcast to be delayed just to make sure all frames
    are shown at the client.
   You'd rather skip the missed frames, and move directly to the newest
    frames at all times.
   Java implements datagrams on top of the UDP protocol by using two
    classes:
     the DatagramPacket which is the data container
       DatagramPacket.
    UDP Datagrams…
A. DatagramSocket
   A DatagramSocket sends as well as receives UDP datagrams.
   To send data, you put the data in a DatagramPacket and send the packet
    using a DatagramSocket.
   To receive data, you take a DatagramPacket object from a DatagramSocket
    and then inspect the contents of the packet.
   The DatagramSocket themselves are very simple creatures.
   In UDP, everything about a datagram, including the address to which it is
    directed, is included in the packet itself.
   The socket only needs to know the local port on which to listen or send.
   DatagramSocket defines four public constructors.
     DatagramSocket() – this creates a DatagramSocket bound to
 The only difference is the port they bind to: the server socket should bind
 By specifying port 0 you ask Java to pick a random available port for you,
  method.
 This tells the socket to time out after 10 seconds of non-responsiveness:
         socket.setSoTimeout(10000);
 Timeouts are even more important for UDP than TCP because many
       receive data and the size of a packet. It is used for receiving data over a
       DatagramSocket.
     DatagramPacket(byte data [], int offset, int size) - the second form allows
    2.2 UDP Datagrams…
   For sending packets, you can create DatagramPacket using the following
    constructors:
       DatagramPacket(byte data [], int length, InetAddress ip, int port) - this
        specifies a target address and port, which are used by a DatagramSocket
        to determine where the data in the packet will be sent.
       DatagramPacket(byte data [], int offset, int length, InetAddress ip, int
        port) – same as the above method except this transmits packets beginning
        at the specified offset into the data.
       DatagramPacket(byte[] data, int length, SocketAddress destination) –
        creates a datagram packet for sending packets of the given length to the
        computer specified by SocketAddress.
       DatagramPacket(byte[] data, int offset, int length, SocketAddress
        destination) – creates a datagram packet for sending packets of the given
        length starting from the given offset. The data is sent to the specified port
        number and the machine specified with the given SocketAddress.
     DatagramPacket Methods
Method                           Description
                                 Returns the address of the source (for datagrams being received) or
InetAddress getAddress( )
                                 destination (for datagrams being sent).
                                 Returns the byte array of data contained in the datagram. Mostly used
byte[] getData( )
                                 to retrieve data from the datagram after it has been received.
                                 Returns the length of the valid data contained in the byte array that
int getLength( )                 would be returned from the getData() method. This may not equal the
                                 length of the whole byte array.
int getOffset( )                 Returns the starting index of the data.
                                 The method returns an integer specifying the remote port. If this
                                 datagram was received from the Internet, this is the port on the host
int getPort( )                   that sent the packet. If the datagram was created locally to be sent to a
                                 remote host, this is the port to which the packet is addressed on the
                                 remote machine.
void setPort(int port)           This method sets the port a datagram is addressed to.
                                 Sets the address to which a packet will be sent. The address is specified
setAddress(InetAddress ip)
                                 by InetAddress.
                                 Sets the data to data, the offset to zero, and the length to number of
void setData(byte[ ] data)
                                 bytes in data.
setData(byte[ ] data, int idx,
                                 Sets the data to data, the offset to idx, and the length to size.
int size)
void setLength(int size)         Sets the length of the packet to size.
   Example: UDP server that sends hello message to all clients
     DatagramSocket sock = null;
     Scanner sc = new Scanner(System.in);
     try {
        sock = new DatagramSocket(7777);
        //buffer to receive incoming data
        byte[] buffer = new byte[8192];
        DatagramPacket incoming = new DatagramPacket(buffer, buffer.length);
        System.out.println("Server socket created. Waiting for incoming data...");
        //communication loop
        while (true) {
           sock.receive(incoming);
           byte[] data = incoming.getData();
           String str = new String(data, 0, incoming.length, “”);
           System.out.println("Client: " + str);
           System.out.print("Server: ");
           String msg = sc.nextLine();
           DatagramPacket dp = new DatagramPacket(msg.getBytes(), msg.getBytes().length,
                                incoming.getAddress(), incoming.getPort());
           sock.send(dp);
        }
     } catch (IOException e) {
        System.err.println("IOException " + e);
     }
Example: UDP client that can connect to the above UDP server
    DatagramSocket sock = null;
    String str;
    Scanner sc = new Scanner(System.in);
    try {
       sock = new DatagramSocket();
       InetAddress host = InetAddress.getByName("localhost");
       int port = 7777;
       while (true) {
          System.out.print("Client: ");
          str = sc.nextLine();
          byte[] b = str.getBytes();
          DatagramPacket dp = new DatagramPacket(b, b.length, host, port);
          sock.send(dp);
          //now receive reply
          byte[] buffer = new byte[8192];
          DatagramPacket reply = new DatagramPacket(buffer, buffer.length);
          sock.receive(reply);
          byte[] data = reply.getData();
          String msg = new String(data, 0, reply.length);
          System.out.println("Server: " + msg);
       }
    } catch (IOException e) { System.err.println("IOException " + e); }
REMOTE METHOD
  INVOCATION
    What is RMI?
   The Remote Method Invocation (RMI) system allows an object running in one
    machine to invoke methods on an object running in another machine.
   RMI provides remote communication between programs written in the Java
    programming language.
   RMI applications often comprise two separate programs: a server and a client.
   A server program creates remote objects, makes references to these objects
    accessible, and waits for clients to invoke methods on these objects.
   A client program obtains a remote reference to one or more remote objects on
    a server and then invokes methods on them.
   RMI provides the mechanism by which the server and the client communicate
    and pass information back and forth.
   Such an application is sometimes referred to as a distributed object application.
   A remote object is an object whose methods can be invoked from another JVM
    that may be running on a different host.
   The object is described by remote interfaces that declare available methods.
    What is RMI...
   RMI is designed in order to support the distributed object model.
   The system architecture consists of three basic layers: the stub/skeleton
    layer, remote reference layer, and transport.
   A specific interface and protocol defines the boundary at each layer.
   Thus, each layer is independent of the next and can be replaced by an
    alternate implementation without affecting the other layers in the system.
   For example, the current transport implementation is TCP based (using
    Java sockets), but a transport based on UDP could be used
    interchangeably.
 marshaling the return value of the call onto the marshal stream
       sequences
      deserialization: decoding of a byte sequence and building of a copy of the
   RRL manages remote references, parameters and stream-oriented
    connection abstraction.
   The remote reference layer is responsible for carrying out the semantics of
    the type of invocation.
   For example this layer is responsible for handling unicast or multicast
    invocation to a server.
   Each remote object implementation chooses its own invocation semantics —
    whether communication to the server is unicast, or the server is part of a
    multicast group.
   The transport is responsible for connection set-up with remote locations
    and connection management, and also keeping track of and dispatching to
    remote objects residing in the transport’s local address space.
   The transport layer sets up the connections to remote address spaces,
    manages them, monitors the connection liveliness, and listens the incoming
    calls.
   In order to dispatch to a remote object, the server’s transport forwards the
    remote call up to the remote reference layer (specific to the server).
   The remote reference layer handles any server-side behavior that needs to be
    done before handing off the request to the server-side skeleton.
   The skeleton for a remote object makes an up-call to the remote object
    What is RMI...
    RMI communicates as follows:
1.   The client obtains a stub instance
2.   The client calls the desired methods on the stub and waits for result
3.   The stub:
      Serializes the information needed for the method invocation (method id
       and arguments)
      Sends information to the skeleton exploiting the RRL abstractions
4.   The skeleton:
      Deserializes the received data
 Calls the method on the object that implements the server (dispatching)
5.   The stub:
      Deserializes the return value
   RMI treats a remote object differently from a non-remote object when the
    object is passed from one JVM to another JVM.
   Rather than making a copy of the implementation object in the receiving JVM,
    RMI passes a remote stub for a remote object.
   The stub acts as the local representative, or proxy, for the remote object and
    basically is, to the client, the remote reference.
   The client invokes a method on the local stub, which is responsible for
    carrying out the method invocation on the remote object.
   A stub for a remote object implements the same set of remote interfaces that
    the remote object implements.
   This property enables a stub to be cast to any of the interfaces that the remote
    object implements.
   However, only those methods defined in a remote interface are available to be
Designing and Implementing the Application Components
   First, determine your application architecture, including which components
    are local objects and which components are remotely accessible. This step
    includes:
   Defining the remote interfaces:
       A remote interface specifies the methods that can be invoked remotely by a client.
       Clients program to remote interfaces, not to the implementation classes of those
        interfaces.
       The design of such interfaces includes the determination of the types of objects that
        will be used as the parameters and return values for these methods.
       If any of these interfaces or classes do not yet exist, you need to define them as well.
   Implementing the remote objects:
       Remote objects must implement one or more remote interfaces.
       The remote object class may include implementations of other interfaces and
        methods that are available only locally.
       If any local classes are to be used for parameters or return values of any of these
        methods, they must be implemented as well.
   Implementing the clients:
       Clients that use remote objects can be implemented at any time after the remote
        interfaces are defined, including after the remote objects have been deployed.
Remote Server
   The server code consists of a remote interface and a class that
    implements the remote interface.
   The interface defines the methods that can be invoked from the
    client.
   Essentially, the interface defines the client's view of the remote
    object.
   The class provides the implementation by implementing the
    interface.
 Remote Server…
A. Remote Interface
 A remote interface extends the interface java.rmi.Remote
   java.rmi.RemoteException.
 This exception is thrown by the RMI system from a remote method invocation
 Remote method calls initiated by the client are actually directed to the stub.
 It works with the other parts of the RMI system to receive requests,
 To generate stubs and skeletons, you use a tool called the RMI compiler,
void bind(String name,     Binds a remote reference to the specified name in this registry. It
Remote obj)                throws RemoteException, AlreadyBoundException, AccessException.
                           Replaces the binding for the specified name in this registry with the
void rebind(String name,   supplied remote reference. If there is an existing binding for the
Remote obj)                specified name, it is discarded. It throws RemoteException,
                           AccessException.
void unbind(String name)   Removes the binding for the specified name in this registry. It
                           throws RemoteException, NotBoundException, AccessException
Remote lookup(String       It returns the remote reference bound to the specified name in this
name)                      registry. It throws RemoteException, NotBoundException,
                           AccessException.
                           Returns an array of the names bound in this registry. The array will
String[] list()            contain a snapshot of the names bound in this registry. It throws
                           RemoteException, AccessException.
    RMI Registry
   Note the following about the Registry.rebind invocation:
       The no-argument version of LocateRegistry.getRegistry synthesizes a
        reference to a registry on the localhost & on the default registry port, 1099.
        You must use an overload that has an int parameter if the registry is
        created on a port other than 1099.
       When a remote invocation on the registry is made, a stub for the remote
        object is passed instead of a copy of the remote object itself. Remote
        implementation objects, such as instances of AddServer, never leave the
        JVM in which they were created. Thus, when a client performs a lookup in
        a server's remote object registry, a copy of the stub is returned. Remote
        objects in such cases are thus effectively passed by reference rather than
        by value.
       For security reasons, an application can only bind, unbind, or rebind
        remote object references with a registry running on the same host. This
        restriction prevents a remote client from removing or overwriting any of
        the entries in a server's registry. A lookup, however, can be requested from
        any host, local or remote.
    RMI Registry
   The Naming class provides methods for storing and obtaining
    references to remote objects in a remote object registry.
   Each method of the Naming class takes as one of its arguments a
    name that is a String in URL format of the form:
         rmi://host:port/name
   Before clients can lookup remote objects on RMI registry, the
    registry first should be started.
   To start the RMI Registry from the command line, use the following
    command:
         start rmiregistry
        RMI Registry…
       Methods of Naming class
Method                                      description
                                            It returns a reference, a stub, for the remote object
                                            associated with the specified name. The method throws
static Remote lookup(String name)           NotBoundException,      MalformedURLException,    and
                                            RemoteException.
                                            It binds the remote object with the given name. It throws
static void bind(String name, Remote r)     AlreadyBoundException,     MalformedURLException,     and
                                            RemoteException.
                                            It destroys the remote object which is bound with the given
static void unbind(String name)             name. It throws RemoteException, NotBoundException, and
                                            MalformedURLException.
                                            It rebinds the specified name to a new remote object. Any
static void rebind(String name, Remote r)   existing binding for the name is replaced. It throws
                                            RemoteException, and MalformedURLException.
                                            It returns an array of the names of the remote objects bound
static String[] list(String name)           to the registry. The name parameter is a registry name in URL
                                            format.       It      throws      RemoteException,        and
                                            MalformedURLException.
    RMI Registry…
   What is the difference between Naming and registry?
   The difference is that the name arguments you pass to java.rmi.Naming are
    in URL format, and include the location of the registry, whereas with
    java.rmi.registry.Registry, the name is just the name.
   Also, the methods on Naming are static.
   For example, you would call something like this:
         Naming.rebind("//host/objName", myObj);
   Whereas with Registry, you need an existing handle on the registry object,
    and you'd call:
         Registry registry =LocateRegistry.getRegistry();
         registry.rebind("objName", myObj);
   Generally, Naming is really just a convenience class that saves you having
    to look up the Registry manually because it performs the registry lookup
    and rebind in one step.
RMI Client
   The client class does not have to do much to access the RMI
    server.
   The only thing the client should do is get reference of remote
    object in order to call its methods.
   This is done using the Naming class.
   Once the client gets reference of remote object, it can call the
    remote methods.
   Example: RMI that accepts two numbers, add them and display the result on client
//remote interface
public interface AddInterface extends Remote{
                                                                        Server side
   double add(double d1, double d2) throws RemoteException;
}
//remote object
public class AddServer extends UnicastRemoteObject implements AddInterface {
   public AddServer() throws RemoteException { }
   public double add(double d1, double d2) throws RemoteException {
     return d1 + d2;
   }
   public static void main(String args[]) {
     try {
        AddServer addServer = new AddServer ();
        Naming.bind("AddServerObject", addServer);
        System.out.println("Server started...");
     } catch (Exception e) {
        System.out.println("Exception: " + e);
     }
   }}
//remote interface
public interface AddInterface extends Remote{
   double add(double d1, double d2) throws RemoteException;
}                                                                              Client side
//client
public class AddClient {
   public static void main(String args[]) {
      try {
         String addServerURL = "rmi://localhost/AddServerObject";
         AddInterface addServerIntf = (AddInterface) Naming.lookup(addServerURL);