DOC

Java Database Connectivity

By Shirley Martin,2014-06-19 06:58
14 views 0
Java Database Connectivity

Week 2: Distributed Communication and Invocation

2.1 Overview and Outcomes Week 2

    Welcome to week 2 of Enterprise and Web Applications.

This week will see us dig into the details of communicating across a networkthe

    foundation of an actual distributed system. We will, in fact, implement a rudimentary middle layer in Java. We have already been able to communicate across a network using Java, but only with a database as we used the JDBC functionality. Now, we will implement simple servers that can accept and respond to arbitrary requests from clients, both local and remote. Put another way, we will be laying down actual code to go with our theory.

    We will be relying heavily on example programs to demonstrate the concepts as they are rather technical. As mentioned in week one, we expect you to retain your grasp of Java from previous classes as we will be advancing into some tough topics (but complete with examples). And although it is understood, we will mention that the content in the week-by-week section does not re-state the content in the textbook. Rather, the content calls out and highlights areas of particular importance to this class which build on the knowledge already available in the textbook. Put another way, you really need to read the textbook (and not just to get your money’s worth).

By the end of this week you will be able:

    ; Explain the UDP and TCP protocols, particularly their strengths and weaknesses ; Use UDP and TCP datagrams to implement data transfer between two Java programs ; Use Java RMI to implement remote object calls in Java, both in server and daemon modes

    ; Describe the concept of marshalling

2.2 Moving from Interprocess to Distributed Communication

    In an ideal world, everything you need would be on a single system. All of the data and pretty much the entire Internet would reside on your hard drive (we will assume you received a good discount on storage). This is the most convenient programming paradigm because everything is locally available. It would be similar to having an entire grocery store available in your refrigeratorthere would be no need to go out.

    This model works for many applications, such as word processors and spreadsheets, which generally do not need any external information. (They would be quite content to have never heard of the Internet, truth be told.) However, we live in an increasingly interconnected world where data and services are scattered to the four winds. We need a programming model that allows us to access these remote capabilities.

    We talked last week about the types of distributed system architectures: single tier, two-tier, and multi-tier. (We will ignore for a while whether or not the tiers are physically on the same system or on different systems.) In essence, a distributed system breaks up a

    previously monolithic application into different components and then proceeds to place them on different systems (i.e. tiers). We are decoupling the consumer and the supplier; we are spreading the activities of an application onto team players (systems).

    In an effort to draw an analogy, let us imagine for a moment a small business run by a single entrepreneur. This one person, Suzette Sellers, does everything, much like our original monolithic application. She sells to customers, orders new product, manages the books (remembering that credits must equal debits), pays the bills, and does anything else. Internally, she has compartmentalized her job function (much like we program in a modular fashion): selling, ordering, and administration. There is no overhead associated with external communication she does everything.

    When her store becomes successful, she finds that she simply cannot do it all (much to her dismay, Congress has yet to add another hour to the day) and requires assistance. Suzette hires Henry Helpers, a capable and likeable chap. This is now similar to our two-tier architecture. Because Suzette and Henry work in the same physical location, this is a logical two-tier system. Communication is quick and easy. Think about two programs on a computer: they can communicate via files, shared memory, pipes, or other constructs. If you are familiar with processing on a UNIX- or Linix-based system, multiple commands are often strung together with pipes.

Suzette’s store does so well that she moves her office into another building to increase

    the amount of retail floor space in her original store. Now Suzette and Henry are in different physical locations but still need to complete the same tasks of selling, ordering, and administration. We have moved into a physical two tier distributed system and things just become more complicated. Suzette and Henry still need to communicate but the previous methods will no longer work. The obvious solution is the telephone, but this changes the dynamic of the entire conversation (for those with passing interests in psychology, just sit stillwe are not thinking that deep). In our computer analogy, we

    now have a client and a server tier where the previous solutions of files, shared memory, or pipes are no longer solutions as they only work within a single system. (We will ignore for the moment various network-based schemes to share these resources as it is those very network-based schemes and devices that we wish to constructbe patient.)

    Suzette and Henry must now specifically locate each other (i.e. phone numbers) before communicating. Conversations will be slower (network latency). Data will need to be shared in different ways (difficult to draw a picture on the phonethe crayon keeps

    breaking on the handset). And finally, the phone lines can go down or have interference (network errors or corruption).

    Yes, we have gained some benefits by spreading out Suzette and Henry (more retail floor space) but we have introduced complexity and latency into the business. Similarly, when a distributed application is placed on different systems (whether physically or logically separated), we also introduce complexity and latency into the application. However, the ability to take advantage of multiple computers is such a powerful incentive that we have

    devised many ways to accommodate our new problems (including pain relieving medications).

The stage is now set to discover how to implement this distributed communication.

2.2.1 Middleware Layer

    If you will remember from last week, we described a distributed application as built in horizontal layers: application, middleware, and platform. We will focus on the middleware this week. By choosing Java, we are explicitly ignoring the platform because Java (in theory) runs exactly the same on any platform that has a Java-compatible runtime environment. We are not yet concerned with what capabilities an application will exhibit other than we will create a “server” component that holds the desired properties and a “client” component that requests these capabilities.

As a side note, we are also assuming that our distributed Java-based application will

    communicate via the magic that is the TCP/IP protocol. This is a fairly solid decision as TCP/IP is the lingua franca of the Internet and most corporate intranets. The actual implementation of the network protocol is of no concern (logically speaking) as long as it looks like TCP/IP. (This is another benefit of encapsulationTCP/IP running on top of

    ATM, Ethernet, or carrier pigeons still looks like TCP/IP to the server and client systems.)

    As a benefit, the same steps needed to create a two-tier architecture can be used to extend to a multi-tier architecture. That is, a server can itself also become a client and request services from another system acting as a server using the same techniques that the first client and server systems employed. Of course, while this logical extension works well in theory, care must be taken because the number of places where failures could occur have just doubled.

    So, while we look at various techniques to implement the middleware layer, we will also look at the design considerations of each. Reaching back to week one, there are at least four challenges to think about: security, failure, concurrency, and transparency. It should be noted that we will blithely ignore and overlook security for now as it will require a discussion of encryption and authentication that is appropriate to later weeks.

2.3 UDP Communication

    The basis of the TCP/IP protocol stack is the Internet Protocol (IP) data packet. IP is a connectionless and stateless protocol. In military parlance, it might be called “fire and forget” because once an IP packet is sent, the sender simply does not care about it anymore. Furthermore, an IP packet may become lost, destroyed, misplaced, or corrupted on the way to its destination. If multiple IP packets are sent, it is possible that they will arrive out of order (which can be disastrous for a set of instructions on assembling a toddler’s toy). IP is quick and easy to use, but definitely not reliable. Think of IP as simple postal envelopes: they can be easily damaged, lost, and delivered out of order. However, IP envelopes are cheap and convenient. (The analogy to a postal

    service is very appropriate as the cost is low per message and the service is usually reliable but there is no capability to trace a wayward envelope.)

    The User Datagram Protocol (UDP) is implemented on top of IP layer. UDP is still a fairly lightweight protocol which means that most of its effort is spent on delivering data. UDP adds two important features: larger “payloads” and data integrity. If a message is

    larger than the size of a single IP envelope, UDP will split the message into multiple IP envelopes, taking care to remember how it split up the original message. UDP guarantees that the data in a single UDP packet in the will arrive exactly as it was sent. What

    happens if one of the IP packets that made up the UDP packet is lost? Then UDP discards the rest of the IP packets and thus the entire UDP packet rather than deliver a damaged UDP packet. This is analogous to sending a four page letter in separate envelopes; if envelope #3 does not arrive, then UDP will throw array the remaining envelopes that did arrive as it has no way to reconstruct the original four page letter.

    UDP is also a stateless and connectionless protocol. So what does this mean? Stateless means that once a message is sent, the sender does not care about it anymore. If the message arrives, then that is fine. If it does not arrive, we do not feel any grief. Connectionless means that there is no continued conversation. The message is complete in and of itself. Think about sending postcards. If we send one postcard from Europe and another from South America, neither of the postcards depend upon each other. They are separate communications.

2.3.1 UDP Design Considerations

    It would seem that UDP would be less than desirable for communications between processes because it cannot guarantee that a message will arrive, or that multiple messages will arrive in the same order that they were sent. Certainly, it would be difficult to have a conversation this way (not unlike early cellular telephones). However, there are definite uses for UDP.

    For client-server applications that transfer relatively small amounts of data, UDP is acceptable. For the simplest application, a client will send a single message to the server and expect a response. If the client does not receive a response within a pre-determined amount of time, the client may send the request again. This is similar to asking a person to repeat an answer. Of course, after asking for the answer so many times, it is likely that we (the client) will just give up. This is the approach taken by the DNS system which resolves host names (like www.regis.edu) into IP addresses. If a DNS server does not

    respond after a couple of seconds, a client will simply accept that no answer is forthcoming and either ask another DNS server or return an error.

    Perhaps a client sends a server a message and the server takes an unusual amount of time to respond. The client will send another request to the server, but at the same time, the server finally responds to the client’s first request. The server will now respond to the

    second request, sending the same reply back. As a client, we can simply ignore the second reply as extraneous (assuming that we have designed our application to keep track

    of which requests were still waiting on an answer so we know when to ignore an extraneous answer).

    Finally, what if a server itself must ask another system for an answer to a client’s query? This is transparent to the original client, but it does delays the final reply to the point where the client may transmit another request.

2.3.2 UDP Example

    UDP communications can be implemented in Java quite easily. However, it should be pointed out that UDP is simply a service to ferry data from point A to point B. UDP does not understand data types or other Java constructs, such as objects. (As an analogy, a postal envelope does not understand nor care about the difference between your electric bill payment and an entry into a fabulous sweapstakes.) To accommodate this understanding, we will use the capability of the String class to convert itself into an array of bytes and back. We are implicitly relying on the String class to correctly convert an array of bytes using the correct code set (that is, where a byte value represents the same letter at both the sender and receiver) given that code sets can change between platforms.

    We will first construct the server, as this creates the capabilities that will then be used by the client. Both the server and client will perform many of the same operations but the server has the additional task of existing in a state where it can receive requests at any time and must respond to them. A client, on the other hand, will only be executed on demand and exit as soon as it receives a response.

2.3.2.1 UDP Server

    The UDP server may look complicated but there is actually very little to it. The server first creates a socket, which is a logical construct that we may attach to an actual port. We have hard-coded the port upon which our server will listen, 7777. You may choose any port between 1024 and 65535 (assuming that it is not already in use).

The server attaches to the port (binds to it in network parlance) and then performs an

    endless loop of listening for any incoming message and sending the same message (known as a datagram) back to its sender. The effect is similar to a mirror.

import java.net.*;

    import java.io.*;

public class UDPServerSimple

    {

     public static void main( String args[] )

     {

     DatagramSocket theSocket = null;

     try

     {

     // + This is the port the server will accept

     // incoming requests on.

     int serverPort = 7777;

     // + Bind the socket to the port.

     theSocket = new DatagramSocket( serverPort );

     // + Declare a storage area to receive data.

     byte[] buffer = new byte[ 1000 ];

     // + As a server, we will listen forever, until

     // the program is forcibly shut down.

     while( true )

     {

     System.out.println( "Waiting for incoming

    request..." );

     // + Create a datagram packet object that

     // can accept data from a socket.

     // + We pass it the storage area (buffer) from

     // above, careful to also pass the total

     // length of the storage area.

     DatagramPacket incomingRequest =

     new DatagramPacket( buffer, buffer.length );

     // + Request data from the socket.

     // + If there is no data, the request will

    block

     // (i.e. wait forever) until data comes in.

     theSocket.receive( incomingRequest );

     System.out.println( "Received message: " +

     new String( incomingRequest.getData(),

     0,

     incomingRequest.getLength()

     )

     );

     // + Create a datagram packaet object that

     // contains the same data received.

     // + Address the datagram back to the original

     // sender.

     DatagramPacket outgoingReply =

     new DatagramPacket(

     incomingRequest.getData(),

     incomingRequest.getLength(),

     incomingRequest.getAddress(),

     incomingRequest.getPort()

     );

     // + Send the datagram back to the sender.

     theSocket.send( outgoingReply );

     System.out.println( " > Reply sent" );

     System.out.println();

     } // while

     }

     catch( SocketException e )

     {

     System.out.println(

     "Exception received concerning the socket: " +

     e.getMessage()

     );

     }

     catch( IOException e)

     {

     System.out.println(

     "Exception received concerning IO: " +

     e.getMessage()

     );

     }

     finally

     {

     // + Always remember to clean up after yourself.

     if ( theSocket != null )

     {

     theSocket.close();

     }

     }

     }

    }

    

2.3.2.2 UDP Client

    The UDP client seems to be much longer in length but that is because we have added in the ability to specify the message to send, the server name, and the port on which the UDP server is listening on the command line, rather than hard-coding it. This approach should allow you to run the program as-is, even though you will run it on your system (which has a different network name and IP address than everybody else’s system).

    The client, similar to the server, first creates a socket that can be bound to a network port. However, we will not bind it to a particular port because we do not carejust as when

    you send a letter, the mailbox you use is irrelevant to the receiver. The client program then resolves the name of the server (first argument) to an IP address, which is what the UDP protocol requires. The second argument is the port that the UDP server is listening on, and the third argument is the actual message (remember to enclose it in double quotes if it contains a space).

    A datagram message is then created and sent to the server. Immediately after sending the message, the client then acts like the server, waiting for a reply. Although the client did not request a specific port, the port that was automatically assigned is included in the outgoing message so that the server can successfully respond back to us.

import java.net.*;

    import java.io.*;

public class UDPClientSimple

    {

     public static void main( String args[] )

     {

     if ( args.length >= 3 )

     {

     DatagramSocket theSocket = null;

     System.out.println();

     try

     {

     // + Bind the socket to a port, but we do not

    specify one

     // because we do not care which we use for

    outbound

     // communications.

     theSocket = new DatagramSocket();

     // + We need to lookup the actual IP address of the server

     // name that was passed as the second

    argument on the

     // command line.

     // + If an actual IP address was passed, it

    will remain

     // an IP address.

     InetAddress theHost = InetAddress.getByName( args[ 0 ]);

     // + Get the port on the server that is

    listening for our

     // message from the third argument on the

    command

     // line.

     int serverPort = Integer.parseInt( args[ 1 ]);

     // + Declare a storage area to send data.

     byte[] message = args[ 2 ].getBytes();

     // + Create the outgoing message package to

    send from the

     // third command line argument.

     DatagramPacket outgoingMessage =

     new DatagramPacket(

     message,

     args[ 2 ].length(),

     theHost,

     serverPort

     );

     // + Send the message

     theSocket.send( outgoingMessage );

     System.out.println( "Destination server: " +

     args[ 0 ] + " (" + theHost.getHostAddress() +

     ") on port " + args[ 1 ]

     );

     System.out.println( " > Sent the message: " +

     args[ 2 ]);

     System.out.println();

     // + Declare a storage area to receive the

    reply.

     byte[] buffer = new byte[ 1000 ];

     // + Create a datagram packet object that

     // can accept data from a socket.

     // + We pass it the storage area (buffer) from

     // above, careful to also pass the total

     // length of the storage area.

     DatagramPacket replyMessage =

     new DatagramPacket( buffer, buffer.length );

     // + Request data from the socket.

     // + If there is no data, the request will block

     // (i.e. wait forever) until data comes in.

     theSocket.receive( replyMessage );

     System.out.println( "Received a packet of " +

     replyMessage.getLength() + " bytes from

    address " +

     replyMessage.getAddress() + " at port " +

     replyMessage.getPort() + "."

     );

     System.out.println( " > The reply message was:

    " +

     new String( replyMessage.getData(), 0,

    replyMessage.getLength())

     );

     System.out.println();

     }

    . . .

     }

     else

     {

     System.out.println( "Usage: UDPClientSimple

     " );

     }

     }

    }

    

2.3.2.3 UDP Example in Action

    Remember to set the CLASSPATH

    All of the examples shown take place in the C:\CS483 directory

    for simplicity. Although not shown, the command has already

    been run to add this directory to the CLASSPATH environment

    variable.

    SET CLASSPATH=C:\CS483;%CLASSPATH%

    If you are using a different directory, ensure that you alter the

    above statement appropriately or pass the classpath to the Java

    runtime environment, similar to the following command.

    java -classpath=C:\CS483 JavaProgramToRun

    Let us now watch the UDP server and client in action (in other words, let us prove that it actually works). We first start the UDP server which opens the port and waits for the first incoming message. It will wait until the program is terminated (it is a very patient program). Although not shown, the UDP server is running on a system with the name “Alpha” (as in the first Greek letter).

    The server gets up and running quickly and then immediately starts waiting for eternity.

    We then run the UDP client which sends a message and then itself waits for a reply.

Report this document

For any questions or suggestions please email
cust-service@docsford.com