[JAVA] I tried to implement a server using Netty

at first

Last time, I tried to create a TCP / IP + NIO / BIO transfer path using libraries such as webSocket and SocketChannel, but I found that the code became quite complicated. This time I will try to realize a server again using Netty.

What is Netty

Simply put, Netty is a framework for developing applications that perform asynchronous communication. Compared to NIO processing realized by SocketChannel, it is no longer necessary to directly operate low-layer APIs (select (), read (), etc.), and it is hidden on the Netty side.

Implementation

NIO implementation on ServerSocket Channel

First of all, I will repost the previous Implementing NIO with ServerSocket Channel.

➀ Create a ServerSocketChannel and listen for client-side access


public class ChannelServer {

    public static void main(String[] args) throws IOException {
        // I/Prepare a thread pool to process O requests
        ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 10, 1000, TimeUnit.MILLISECONDS, 
                new ArrayBlockingQueue<Runnable>(100));

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(1234));

        while (true) {
            SocketChannel socketChannel = serverSocketChannel.accept();

            if (socketChannel != null) {
                //Commit the request to the thread pool
                executor.submit(new ChannelServerThread(socketChannel));
            }
        }
    }
}

② Thread that processes the request


public class ChannelServerThread implements Runnable {

    private SocketChannel socketChannel;
    private String remoteName;

    public ChannelServerThread(SocketChannel socketChannel) throws IOException {
        this.socketChannel = socketChannel;
        this.remoteName = socketChannel.getRemoteAddress().toString();
        System.out.println("client:" + remoteName + " access successfully!");
    }

    // I/Handle O request
    @Override
    public void run() {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        ByteBuffer sizeBuffer = ByteBuffer.allocate(4);
        StringBuilder sb = new StringBuilder();
        byte b[];
        //Read data and length from socketChannel and output to standard output
        while(true) {
            try {
                sizeBuffer.clear();
                int read = socketChannel.read(sizeBuffer);
                if (read != -1) {
                    sb.setLength(0);
                    sizeBuffer.flip();
                    int size = sizeBuffer.getInt();
                    int readCount = 0;
                    b = new byte[1024];
                    while (readCount < size) {
                        buffer.clear();
                        read = socketChannel.read(buffer);
                        if (read != -1) {
                            readCount += read;
                            buffer.flip();
                            int index = 0 ;
                            while(buffer.hasRemaining()) {
                                b[index++] = buffer.get();
                                if (index >= b.length) {
                                    index = 0;
                                    sb.append(new String(b,"UTF-8"));
                                }
                            }
                            if (index > 0) {
                                sb.append(new String(b,"UTF-8"));
                            }
                        }
                    }
                    System.out.println(remoteName +  ":" + sb.toString());
                }
            } catch (Exception e) {
                System.out.println(remoteName + "access colsed");
                try {
                    socketChannel.close();
                } catch (IOException ex) {
                }
                break;
            }
        }
    }
}

NIO implementation with Netty

➀ Process that waits for access on the client side


public class EchoServer {
    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }

    public void start() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            ServerBootstrap sb = new ServerBootstrap();
            //Thread pool binding
            sb.group(group)
                    .channel(NioServerSocketChannel.class)
                     //Port number binding
                    .localAddress(this.port)
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("connected...; Client:" + ch.remoteAddress());
                            ch.pipeline().addLast(new EchoServerHandler());
                        }
                    });
            //Asynchronous binding of server
            ChannelFuture cf = sb.bind().sync();
            System.out.println(EchoServer.class + " started and listen on " + cf.channel().localAddress());
            //Close server channel
            cf.channel().closeFuture().sync();
        } finally {
            //Unbind thread pool
            group.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws Exception {
        //entrance
        new EchoServer(66666).start();
    }
}

② The one who processes the request


public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("server channelRead...; received:" + msg);
        ctx.write(msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("server channelReadComplete..");
        //WriteAndFlush in empty buffer,Close the connection
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("server occur exception:" + cause.getMessage());
        cause.printStackTrace();
        ctx.close();
    }
}

change point

** The amount of code has been greatly reduced. ** ** This is to hide APIs such as read () and Buffer operations from the Netty side and provide a convenient high-layer API. For example, channelRead () method of EchoServerHandler class: When data from the client side is accepted, it is converted to String internally, so this method is called.

Summary

This time I tried to implement the server using Netty. I will introduce the cooperation with the client side next time.

Recommended Posts

I tried to implement a server using Netty
I tried using Log4j2 on a Java EE server
I tried using the GitHub repository as a library server
I tried using Hotwire to make Rails 6.1 scaffold a SPA
I tried to implement a buggy web application in Kotlin
[Rails] I tried to implement "Like function" using rails and js
I tried to implement the Iterator pattern
I tried to implement ModanShogi with Kinx
[Unity] I tried to make a native plug-in UniNWPathMonitor using NWPathMonitor
I tried to build a simple application using Dockder + Rails Scaffold
I tried to make a simple face recognition Android application using OpenCV
I tried using Gson
java I tried to break a simple block
[Rails] I tried to implement a transaction that combines multiple DB processes
I tried to develop a man-hour management tool
I tried to develop a DUO3.0 study website.
I tried to implement deep learning in Java
I tried to create a LINE clone app
I tried using TestNG
I tried using Galasa
I tried to make a talk application in Java using AI "A3RT"
I tried to develop a website to record expenses.
I tried to break a block with java (1)
I tried to implement a function equivalent to Felica Lite with HCE-F of Android
[Java] I tried to connect using a connection pool with Servlet (tomcat) & MySQL & Java
I tried using a database connection in Android development
I tried using the Server Push function of Servlet 4.0
I tried to implement TCP / IP + BIO with JAVA
I tried to implement Firebase push notification in Java
I tried to decorate the simple calendar a little
I tried to operate SQS using AWS Java SDK
I tried to create a Clova skill in Java
I tried to make a login function in Java
I tried to implement Stalin sort with Java Collector
I tried to implement the Euclidean algorithm in Java
I tried scraping a stock chart using Java (Jsoup)
I tried to build an environment using Docker (beginner)
I tried using azure cloud-init
I tried using Apache Wicket
I tried to verify yum-cron
I tried using Wercker to create and publish a Docker image that launches GlassFish 5.
I want to implement it additionally while using kotlin on a site running Java
[Swift] I tried to implement exception handling for vending machines
I tried to implement the like function by asynchronous communication
I tried to create a java8 development environment with Chocolatey
I tried adding a separator line to TabLayout on Android
I tried to modernize a Java EE application with OpenShift.
[Rails] I tried to create a mini app with FullCalendar
I want to implement a product information editing function ~ part1 ~
[Swift] I tried to implement the function of the vending machine
I tried to introduce UI animation to Pokedex using Poké API
I tried to link chat with Minecraft server with Discord API
I tried to build the environment little by little using docker
[Rails] I tried to implement batch processing with Rake task
I tried to convert a string to a LocalDate type in Java
I tried using Dapr in Java to facilitate microservice development
I tried to make a client of RESAS-API in Java
I tried to create a padrino development environment with Docker
I tried to get started with Swagger using Spring Boot
I made a Dockerfile to start Glassfish 5 using Oracle Java
I tried using anakia + Jing now