Monday, February 6, 2012

Java 7 new features - 7. NIO2 : E. Asynchronous TCP server/client example


<< Previous Table of Categories Next>>


To illustrate how Asynchronous works, there are some delay in both the server and the client. You can easily play this on your PC to understand how the Asynchronous channels work.
Asynchronous TCP Server
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class AsynchronousTcpServer
{
    public static void main(String[] args)
    {

        final int SERVER_PORT = 9001;
        final String SERVER_IP = "127.0.0.1";

        //create asynchronous server-socket channel bound to the default group
        try (AsynchronousServerSocketChannel asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open())
        {
            if (asynchronousServerSocketChannel.isOpen())
            {
                //bind to local address
                asynchronousServerSocketChannel.bind(new InetSocketAddress(SERVER_IP, SERVER_PORT));

                //display a waiting message 
                System.out.println("Waiting for connections ...");
                while (true)
                {
                    Future<AsynchronousSocketChannel> asynchronousSocketChannelFuture =
                        asynchronousServerSocketChannel.accept();
                    try (AsynchronousSocketChannel asynchronousSocketChannel = asynchronousSocketChannelFuture.get())
                    {
                        System.out.println("Incoming connection from: " + asynchronousSocketChannel.getRemoteAddress());
                        ByteBuffer incomingBuffer = ByteBuffer.allocateDirect(1024);
                        //receiving data
                        asynchronousSocketChannel.read(incomingBuffer, incomingBuffer,  new CompletionHandler<Integer, ByteBuffer>()
                        {
                            public void completed(Integer result, ByteBuffer buffer)
                            {
                                buffer.flip();
                                String msgReceived = Charset.defaultCharset().decode(buffer).toString();
                                System.out.println("Msg received from the client : " + msgReceived);
                            }
                            public void failed(Throwable exc, ByteBuffer buffer)
                            {
                                throw new UnsupportedOperationException("read failed!");
                            }                                             
                        });
                        try
                        {
                            Thread.sleep(5000);
                        }
                        catch(Exception e){}
                        
                        //replying data
                        ByteBuffer outgoingBuffer = ByteBuffer.wrap("World".getBytes());
                        asynchronousSocketChannel.write(outgoingBuffer).get();
                    }
                    catch (IOException | InterruptedException | ExecutionException ex)
                    {
                        System.err.println(ex);
                    }
                }
            }
            else
            {
                System.out.println("The asynchronous server-socket channel cannot be opened!");
            }
        }
        catch (IOException ex)
        {
            System.err.println(ex);
        }
    }
}
Asynchronous TCP Client
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutionException;

public class AsynchronousTcpClient
{
    static boolean completed = false;
    public static void main(String[] args)
    {
        
        final int SERVER_PORT = 9001;
        final String SERVER_IP = "127.0.0.1";
       
        ByteBuffer receivingBuffer = ByteBuffer.allocateDirect(1024);
        ByteBuffer sendingBuffer = ByteBuffer.wrap("Hello".getBytes());
               
        //create asynchronous socket channel
        try (final AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open())
        {
            if (asynchronousSocketChannel.isOpen())
            {
                //connect this channel's socket
                Void connect = asynchronousSocketChannel.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT)).get();
                if (connect == null)
                {
                    System.out.println("Local address: " + asynchronousSocketChannel.getLocalAddress());
                    
                    //sending data
                    asynchronousSocketChannel.write(sendingBuffer).get();
                    asynchronousSocketChannel.read(receivingBuffer, receivingBuffer,  new CompletionHandler<Integer, ByteBuffer>()
                    {
                        public void completed(Integer result, ByteBuffer buffer)
                        {
                            buffer.flip();
                            String msgReceived = Charset.defaultCharset().decode(buffer).toString();
                            System.out.println("Msg received from server : " + msgReceived);
                            completed = true;
                        }
                        public void failed(Throwable exc, ByteBuffer buffer)
                        {
                            completed = false;
                            throw new UnsupportedOperationException("read failed!");
                        }                                             
                  });
                  
                  while(!completed)
                  {
                      try
                      {
                          Thread.sleep(1000);
                      }
                      catch(Exception e){}
                      System.out.println("Waiting for response from the server");
                  } 
                  
                }
                else
                {
                    System.out.println("The connection cannot be established!");
                }
            }
            else
            {
                System.out.println("The asynchronous socket channel cannot be opened!");
            }
        }
        catch (IOException | InterruptedException | ExecutionException ex)
        {
            System.err.println(ex);
        }
      
    }
}

4 comments:

  1. Can the asynch cllient be used to talk to a tcp server that may not be written as an asych server, but rather a c++ server. does not client and server both have to use these classes?

    ReplyDelete
    Replies
    1. Like the other anonymous said, it does not matter what the server does as long as the data that is being exchanged is understood. And having an asynch client has nothing to do with having an asynch server. It only means that your client will not be stopped/blocked while waiting for a response from the server. However, normally, servers are asynch. In my opinion, a server that is not asynch is a bad model unless its use is rare and client size is extra small.

      Delete
  2. If you're using byte arrays on both ends, it shouldn't matter.

    ReplyDelete
  3. Hi, This is Chandrika from Chennai. I have read your blog and I got some knowledgeable information through this blog. Really useful blog. Keep update your blog.

    Regards...
    Java Training Chennai

    ReplyDelete