Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin
Wiki Markup
{scrollbar}

This tutorial is designed to help you in writing a client and server using the MINA framework. In this tutorial we will write a server that displays memory usage for clients. This has some real world applicability in that you can place similar logic into any program in order to monitor the amount of memory that your program is using.

Info
titleVersion Note

This tutorial has been verified on MINA 2.0.0 M3.

Building the code

For now MINA 2.0 final isn't released, but you can download the latest built version (2.0.0-M3).

If you prefer to build the code from the trunk, and need assistance to do so, please consult the Developer Guide.

The Application


The figure above depicts the sample UDP server. The Server is listening on the port 18567. The Client connects to the Server and sends the memory usage data. The figure above depicts two clients connected to the Server.

The Application Execution Flow

  1. The Server listens for incoming requests on port 18567
  2. The Client connects to the Server. The Server adds a Tab on Session Created event
  3. The Clients sends memory usage data to Server
  4. The Server adds the data received from Client in the tab added in Step 2

Server Code analysis

We will begin by looking at the code found in the org.apache.mina.example.udp package under mina-examples. To keep life simple, we shall concentrate on MINA related constructs only.

To construct the server, we shall have to do the following:

  1. Create a Datagram Socket to listen for incoming Client requests (See MemoryMonitor.java)
  2. Create an IoHandler to handle the MINA framework generated events (See MemoryMonitorHandler.java)

Here is the first snippet that addresses Point# 1:

No Format
NioDatagramAcceptor acceptor = new NioDatagramAcceptor();
acceptor.setHandler(new MemoryMonitorHandler(this));

Here, we create a NioDatagramAcceptor to listen for incoming Client requests, and set the IoHandler.The variable 'PORT' is just an int. The next step is to add a logging filter to the filter chain that this DatagramAcceptor will use. LoggingFilter is a very nice way to see MINA in Action. It generate log statements at various stages, providing an insight into how MINA works.

No Format
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
chain.addLast("logger", new LoggingFilter());

Next we get into some more specific code for the UDP traffic. We will set the acceptor to reuse the address

No Format
DatagramSessionConfig dcfg = acceptor.getSessionConfig();
dcfg.setReuseAddress(true);acceptor.bind(new InetSocketAddress(PORT));

Of course the last thing that is required here is to call bind().

IoHandler implementation

There are three major events of interest for our Server Implementation

  • Session Created
  • Message Received
  • Session Closed

Lets look at each of them in detail

Session Created Event

No Format
@Override
public void sessionCreated(IoSession session) throws Exception {
     SocketAddress remoteAddress = session.getRemoteAddress();
     server.addClient(remoteAddress);
}  

In the session creation event, we just call addClient() function, which internally adds a Tab to the UI

Message Received Event

No Format
 @Override
 public void messageReceived(IoSession session, Object message) throws Exception {
        if (message instanceof IoBuffer) {
            IoBuffer buffer = (IoBuffer) message;
            SocketAddress remoteAddress = session.getRemoteAddress();
            server.recvUpdate(remoteAddress, buffer.getLong());
        }
 }

In the message received event, we just dump the data received in the message. Applications that need to send responses, can process message and write the responses onto session in this function.

Session Closed Event

No Format
@Override
public void sessionClosed(IoSession session) throws Exception {
    System.out.println("Session closed...");
    SocketAddress remoteAddress = session.getRemoteAddress();
    server.removeClient(remoteAddress);
}

In the Session Closed, event we just remove the Client tab from the UI

Client Code Analysis

In this section, I will try to explain the client code. One note to make is that I left out the debugging/logging for brevity's sake. So here goes....

To implement the Client we need to do following:

  • Create Socket and Connect to Server
  • Set the IoHandler
  • Collect free memory
  • Send the Data to the Server

We will begin by looking at the file MemMonClient.java, found in the org.apache.mina.example.udp.client java package. The first few lines of the code are simple and straightforward.

No Format
connector = new NioDatagramConnector();
connector.setHandler( this );
ConnectFuture connFuture = connector.connect( new InetSocketAddress("localhost", MemoryMonitor.PORT ));

Here we create a NioDatagramConnector, set the handler and connect to the server. One gotcha I ran into was that you must set the host in the InetSocketAddress object or else nothing seems to work. This example was mostly written and tested on a Windows XP machine, so things may be different elsewhere. Next we will wait for acknowledgment that the client has connected to the server. Once we know we are connected, we can start writing data to the server. Here is that code:

No Format
connFuture.addListener( new IoFutureListener(){
            public void operationComplete(IoFuture future) {
                ConnectFuture connFuture = (ConnectFuture)future;
                if( connFuture.isConnected() ){
                    session = future.getSession();
                    try {
                        sendData();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    log.error("Not connected...exiting");
                }
            }
        });

Here we add a listener to the ConnectFuture object and when we receive a callback that the client has connected, we will start to write data. The writing of data to the server will be handled by a method called sendData. This method is shown below:

No Format
private void sendData() throws InterruptedException {
        for (int i = 0; i < 30; i++) {
            long free = Runtime.getRuntime().freeMemory();
            IoBuffer buffer = IoBuffer.allocate(8);
            buffer.putLong(free);
            buffer.flip();
            session.write(buffer);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                throw new InterruptedException(e.getMessage());
            }
        }
}

This method will write the amount of free memory to the server once a second for 30 seconds. Here you can see that we allocate a IoBuffer large enough to hold a long variable and then place the amount of free memory in the buffer. This buffer is then flipped and written to the server.