Most Read This Week
Java Industry News
Channel: A Communication Components
Channel: A Communication Components
Mar. 1, 1996 12:00 AM
In this way, one can write client/server applications by manually modifying and extending Java client/server exemplary codes according to the specification of a new problem. After experiencing this sort of "cut-and-paste" model, one realizes that this is not the best way of developing applications. This approach has at least these pitfalls:
To have a more modular and reusable approach, we can build communication objects to encapsulate and generalize the necessary send and receive behaviors. In this article, we would like to introduce a simple yet effective Java communication component called Channel. With this communication object class, you can create new Channels dynamically in any distributed application for communicating general objects among your application components. This is like adding a plug-and-play ear and mouth-like sensory module to a robot (or softbot) to allow it to communicate with other robots (or softbots).
The construction of Channel objects is in the spirit of a distributed objects component model to build generic reusable and useful software components that can be assembled dynamically to form new applications seamlessly. The Channel component is compact and lightweight so that it can be created and used easily without any additional programming. While the Java Beans  allow components to communicate dynamically by providing the context for arrangement and interaction in container, the Channel component simply provides an alternative encapsulation for dynamic interaction among application components.
What is a Channel?
If an application component wishes to send a message to another application component with an active Channel component, it invokes its own Channel component's send() method to open a socket connection with the specified host and port and transmits the message across the connection. The send() method ensures the delivery of the message by waiting for a simple acknowledgment message from the receiving Channel. The application component can send messages to many different Channels of different application components. Indeed, an application component can have more than one communication channel by creating multiple Channel objects with different port numbers. The acknowledgment required by the send() method also eliminates premature socket reset if a second message is sent to the same channel too soon.
Using Object Serialization , the Channel component deals with generic message format instead of hardcoding the anticipated primitive data types for messages into the message receiving codes where in some applications (we will point out later) the number of possible message types is tremendous to cope with. Unconstrained message format also allows message interpretation (and invocation of relevant message handler) to be delayed at a higher and more appropriate application level.
Figure 2 shows the schematic diagram of a Channel component, its interactions with the application components, the internal view of a Channel, its interaction with socket and the use of object serialization.
Building a Communication Channel
A Channel object has two private protected variables: a ServerSocket, listen_socket: and a MessageQueue, mailbox. Upon construction, a new Channel object creates a ServerSocket (listen_socket) for a specified port and associates its MessageQueue (mailbox) to the reference of the mailbox provided by the application component which creates it. As a subclass of Thread, the new Channel object then starts itself to listen on the specified port with the ServerSocket, ready to accept connection and receive messages from other application components.
Socket client = listen_socket.accept(); and creates a client Socket to accept connection when requested. Anticipating generic message object rather than specific data types, an ObjectInputStream (sin) from the Object Serialization package  is created from the client socket,
ObjectInputStream sin = new ObjectInputStream(client.getInputStream() ); and a DataOutputStream (sout) is also created for sending simple acknowledgment bytes on receiving messages.
Once engaged in an accepted connection, the Channel thread enters an inner while-loop to receive message as serialized object from the "client",
Message msg = (Message)sin.readObject(); and cast it to the appropriate Message type. A single acknowledgment byte is replied as an acknowledgment via the DataOutputStream. The received message, message, is then immediately appended to the message queue provided by the application component,
mailbox.put( message ); and the Channel object is ready to receive the next incoming message.
When the client has finished sending the message and closed its connection, an EOFException exception will be caught by the server Channel object waiting to receive message. The server will then clean up by closing the relevant socket and streams. Figure 3 shows the handshaking between the sender and receiver.
With a perpetual thread to listen for messages by a Channel object on a given port, an application component can process the messages (perhaps by a different thread) at its own convenience. This strategy decouples and thus modularizes the message receiving and message processing processes. Though it is possible to have a multi-threaded Channel server that spawns a new thread for each client connection request such as the one described in  (p.146), it is usually not necessary as the message receiving process is short and simple.
public void send( Object message, String hostname, int port ). In this send() method, a client Socket (sender) is created,
Socket sender = new Socket( hostname, port ); As in the case of message receiving but conversely, an ObjectOutputStream, out, is created to serialize message object across the socket's output stream,
ObjectOutputStream out = new ObjectOutputStream(sender.getOutputStream() );
An application component can therefore use its communication Channel to send messages to different hosts and ports by invoking this send() method conveniently as long as the hosts and ports are known.
A variant assuming communication within local host would be to omit the hostname,
public void send( Object message, int port ) which will find the local host using InetAddress's (in java.net package) class and instance methods in that order,
String hostname = InetAddress.getLocalHost().getHostName(); and invoke the more general send() method as described above.
Another variant is to specify an Internet IP address instead of hostname. Yet another variant is to send an array of messages by a single invocation of the send() method by replacing the first argument with "Object messages" and writing the message objects in a loop. We shall omit their details here.
The MessageQueue class (Listing 2) extends a circular Queue data structure with synchronization mechanism for a producer/consumer type of concurrent access using Semaphore objects. As queue and semaphore are fundamental data structure and synchronization mechanism respectively in computer science, and their Java implementations are easily available (for example, see http://www.digitalfocus.com/digitalfocus/faq/howdoi.html#T_1), we only show their abstract classes in Listings 3 and 4 instead of our full implementation to save space.
The constructor of the MessageQueue class basically invokes its super(Queue) class's constructor to allocate and initialize a queue of objects followed by creating two Semaphores.
The put() and get() methods follow the semantics of the append() and remove() methods of a first-in-first-out queue respectively. They are implemented by simply calling the corresponding super class's instance methods surrounded by appropriate synchronization primitives.
An Example to Use Channel
This Test (class) program sends a "Hello" message with the local hostname and current time and date to any number of hosts as specified on the argument list and displays messages that it continues to receive. If no argument is specified, no message will be sent out.
The Test program first creates a MessageQueue, m, and a Channel, c. Then, it constructs a "Hello" message: "Hello" string in the intention field, local hostname as sender, and current time and date as content. A loop is used to send the constructed message using Channel's send() method,
for (int i = 0; i
Finally, the Test program loops forever to listen for incoming messages. When its Channel thread has deposited message in its message queue, it removes them from the queue and displays them. Otherwise, it will be blocked when its message queue is empty,
msg = (Message)c.receive(); To test this program, you can run a copy of it without argument on a host to act as "server" and run other copies on other hosts to send messages to the server. An exemplary output is shown in Listing 6 where "grus", "marten" and "corona" are hostnames.
A simple modification to the Test program actually gives us a template for writing a server program (or service agent) that provides appropriate services based on messages received from clients (Listing 7). This example and the template illustrate how Channel object can provide a high-level programming interface for application components to perform generic message communication.
The Channel object described here presents a first step towards engineering communication software components for distributed computing applications. More sophisticated re-synchronization and recovery mechanisms should be in place to achieve reliability and robustness in mission critical applications.
Conclusion and Future Outlook
Indeed, the communication Channel could form a basic component in the implementation and application of the emerging software agent technologies  where agent communication is a key attribute in any multi-agent system. The Channel object thus allows one to agentify a non-agent software component in the communication aspect. The notion of generic message format and passing using object serialization is important for realizing any agent communication language whose content language varies with messages and application domains (e.g. ). In general, without object serialization, an implementation will look clumsy in order to cope with potentially enormous combinations of message types in an open computing environment. Last but not least, the proposed Channel class has been used in the prototyping of software agent research and applications [6, 7].
Reader Feedback: Page 1 of 1
Subscribe to the World's Most Powerful Newsletters
Today's Top Reads