This tutorial shows how to create a simple netty client with command-line interface

Prerequisite - a string-based protocol server, can be the one from Netty server tutorial.

The base code of a client is similar to the one of the server:


    public class CLIClient
    {
        ChannelFuture future;
        EventLoopGroup workergroup;

        public CLIClient(String host, int port)
        {
            workergroup = new NioEventLoopGroup();
            try
            {
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(workergroup);
                bootstrap.channel(NioSocketChannel.class);
                bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
                bootstrap.handler(new ChannelInitializer<SocketChannel>()
                {
                    @Override
                    protected void initChannel(SocketChannel ch)
                    {
                        //TODO
                    }
                });

                future = bootstrap.connect(host, port).sync();
            }
            catch (Exception e)
            {
                e.printStackTrace();
                workergroup.shutdownGracefully();
                System.exit(1);
            }
        }

        void shutdown()
        {
            try
            {
                workergroup.shutdownGracefully();
                future.channel().closeFuture().sync();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

Its constructor has a 'host' parameter (a target to connect to) and 'port' parameter.

Then, write a main class that starts the client:


    public class ClientStarter
    {
        //Apache logger
        static Logger LOGGER;

        public static void main(String[] strings)
        {
            LOGGER = LogManager.getLogger("Client", new ParameterizedMessageFactory());
            String host = "localhost";
            // This is the same port the server is listening to
            int port = 59433;
            CLIClient cliClient = new CLIClient(host, port);

            // prepare the input from console
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String s;
            try
            {
                LOGGER.info("Console input ready");
                while ((s = reader.readLine()) != null)
                {
                    if (s.equals("exit"))
                    {
                        cliClient.shutdown();
                        break;
                    }
                    else
                    {
                        // This statement passes other strings to the client to handle
                        cliClient.future.channel().writeAndFlush(s);
                    }
                }
                reader.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
                System.exit(1);
            }

        }
    }

Now test the connection: start the server; when the server is ready, start this client. The client will throw an exception if it couldn't connect to a server on that port. As we are using string protocol, we can add existing handlers to decode ingoing and encode outgoing string messages - io.netty.handler.codec.string.StringDecoder and io.netty.handler.codec.string.LineEncoder:


    bootstrap.handler(new ChannelInitializer<SocketChannel>()
        {
            @Override
            protected void initChannel(SocketChannel ch)
            {
                ch.pipeline().addLast(new LineEncoder(LineSeparator.UNIX), new StringDecoder(), new ResponseHandler());
            }
        });
 

Now anything we write into client console will be auto-encoded to a String message by the LineEncoder; likewise, responses from the server will be decoded to a String and passed to a ResponseHandler, which is a custom handler that logs the messages:


    public class ResponseHandler extends ChannelInboundHandlerAdapter
    {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg)
        {
            // The message was decoded to a string by the StringDecoder, so we can cast it safely.
            String mString = (String) msg;
            ClientStarter.LOGGER.info(mString.trim());
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
        {
            cause.printStackTrace();
        }
    }

Final client code:


    public class CLIClient
    {
        ChannelFuture future;
        EventLoopGroup workergroup;

        public CLIClient(String host, int port)
        {
            workergroup = new NioEventLoopGroup();
            try
            {
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(workergroup);
                bootstrap.channel(NioSocketChannel.class);
                bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
                bootstrap.handler(new ChannelInitializer<SocketChannel>()
                {
                    @Override
                    protected void initChannel(SocketChannel ch)
                    {
                        ch.pipeline().addLast(new LineEncoder(LineSeparator.UNIX), new StringDecoder(), new ResponseHandler());
                    }
                });

                future = bootstrap.connect(host, port).sync();
                ClientStarter.LOGGER.info("Connected to {} on {}", host, port);
            }
            catch (Exception e)
            {
                e.printStackTrace();
                workergroup.shutdownGracefully();
                System.exit(1);
            }
        }

        void shutdown()
        {
            try
            {
                ClientStarter.LOGGER.info("Shutting down");
                workergroup.shutdownGracefully();
                future.channel().closeFuture().sync();
                ClientStarter.LOGGER.info("Shutdown successful");
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

Now you can further enhance your server and client to fit your needs. This is the end of the tutorial.

Main page