Objects and Client - Server Connections
Objects and Client - Server Connections
In keeping with the code examples used in the previous articles, Java will be
the language used to implement the concepts in code. One of the reasons
that I like to use Java is because you can download the Java compiler for
personal use at the Sun Microsystems Web site http://java.sun.com/. You can
download the standard edition, J2SE 5.0, at
http://java.sun.com/j2se/1.5.0/download.jsp to compile and execute these
applications. I often reference the Java J2SE 5.0 API documentation and I
recommend that you explore the Java API further. Code listings are provided
for all examples in this article as well as figures and output (when
appropriate). See the first article in this series for detailed descriptions for
compiling and running all the code examples.
import java.io.*;
import java.util.*;
import java.io.*;
import java.net.*;
clientOutputStream.writeObject(joe);
joe= (Employee)clientInputStream.readObject();
clientOutputStream.close();
clientInputStream.close();
×
Listing 2: The Client
The complete code for the Server class is shown in Listing 3.
import java.io.*;
import java.net.*;
try {
System.out.println("Server Waiting");
employee .setEmployeeNumber(256);
employee .setEmployeeName("John");
serverOutputStream.writeObject(employee);
serverInputStream.close();
serverOutputStream.close();
} catch(Exception e) {System.out.println(e);
}
}
×
Compiling and Running the System
I compiled the code using a DOS Shell. On certain machines it is called a DOS
Shell and on others it is called a Command Prompt. They and equivalent and I
will show examples of both. Eventually we will need two of these DOS Shells,
one to run the Server and one for the Client. You can open a DOS Shell in the
Programs->Accessories option.
Type the following code at the command prompt to compile all three of the
files.
In one of the DOS Shells, type in the following line at the command prompt:
In a separate DOS Shell, start the Client with the following line.
If all is well, you will see that the employeeNumber and the employeeName
both were changed. You can put some specific identification in the print
statements to provide further assurance.
With the circuit complete, the Server should exit cleanly, as shown in Figure 4.
At a very basic level, there is a simple code enhancement that will allow the
Server to handle multiple clients. In fact, the server can also handle multiple
transactions from the same client. For example, by adding a simple while
loop, we can provide this behavior. Listing 4 contains this enhancement.
import java.io.*;
import java.net.*;
try {
while (true) {
System.out.println("Server Waiting");
ObjectOutputStream serverOutputStream =
ObjectOutputStream(pipe.getOutpu
employee .setEmployeeNumber(256);
employee .setEmployeeName("John");
serverOutputStream.writeObject(employee);
serverInputStream.close();
serverOutputStream.close();
×
} catch(Exception e) {System.out.println(e);
}
}
The two lines in bold represent the code required to implement the loop.
Note that several lines of the code must reside within the loop.
The basic concept here is that once the Server handles a single client
transaction, it closes the input/output stream and then loops back to wait for
the next client transaction. Each time the following line is encountered, the
Server simply waits.
Listens for a connection to be made to this socket and accepts it. The
method blocks until a connection is made.
A new Socket s is created and, if there is a security manager, the security
manager’s checkAccept method is called with
s.getInetAddress().getHostAddress() and s.getPort() as its arguments to
ensure the operation is allowed. This could result in a SecurityException.
To test the use of multiple clients, simply create more than one client. Make
sure that each client uses the IP address of the server and you are ready to
test. Figure 5 shows how my system looks when I am running the Server with
2 different clients.
×
Identifying the Client
One very useful piece of information that the Server can collect is some sort
of client ID. We can actually embed this in the Employee object itself. This ID
can take the form of a simple ID number or we can inspect any attribute on
the object. In this example, rather than use the employeeNumber attribute,
let’s use the employeeName attribute. This will make it easier for us to read
and identify the client more easily.
On the server side, we can add a line of code to print out the name of the
specific Employee object.
Figure 6 shows what happens when we use two clients. The first Client has
the name of Joe and the second the name of Mary. You can see the specific
information printed in the client Command Prompt. The Server Command
Prompt is more interesting. Note that the Server handles the message from
both Joe and Mary and then prints their name. This illustrates that the Server
can indeed handle multiple clients. It is important to realize how nicely all of
this is packaged into the objects and how the objects are marshaled across
the network.
×
C:column22cs> ipconfig
This command will provide the appropriate IP address for the server. Simply
change the loopback string, “127.0.0.1”, to the IP address of the Server.
For example, let’s make a change to the Client. Let’s say that we want to add a
last name to the Employee object as seen in Listing 5.
import java.io.*;
import java.util.*;
Note the lines in bold. These lines add the functionality of the lastName.
However, this obviously changes the Employee class. For example, if the
Client compiles on one machine with this change and the Server compiles on
another with the old version of Employee, a problem will arise (see Figure 7).
The Employee class the Server uses is different than the one that the Client
uses – and this is not allowed. The fact that this can even happen is because
Java dynamically loads all classes – there is no linked executable. This is a
tricky configuration management issue. If you update a class you must make
sure that all distributions of that class get updated.
In this example, the Employee class was updated on the Client, but not the
Server. Since the Server was expecting a specific Employee class, an exception
was generated when it received a different one. The interesting thing to look
at is the fact that a class is assigned a serialVersionUID. When these two
serialVersionUIDs do no match, a problem is identified. This is as much a
security issue as it is a programming issue.
As we have seen, moving an object from one place to another is often a tricky
proposition. In languages such as Java and the .Net languages, while the
ability to load objects dynamically is a major strength, we have to deal with
the problem of keeping the class versions in sync.
While the example of this article is complete and useful, it is quite basic. There
are many more fascinating topics to explore regarding client/server
applications.
References
Tyma, Paul, Gabriel Torok and Troy Downing: Java Primer Plus. The Waite
Group, 1996.
www.javasoft.com