Getting started with Netty (NIO programming and Netty client server example)

1.NIO programming

1.1 what is NIO programming

One understanding is New I/O, because compared with the previous I/O class library, it is new. More people like to call it non block I/O. since non block I/O can better reflect the characteristics of NIO, subsequent NIO refers to non block I/O

1.2 introduction to NiO class library

1. Buffer

	In flow oriented I/O In, you can write or read data directly to Stream Object, in NIO In the library, all data is processed with buffers. When writing data, it is also written to the buffer.

Buffer is essentially an array, usually a byte array. Buffer provides structured access to data and maintains read-write limit and other information

2. channel

	The difference between channel and flow is that channel is bidirectional, and flow knowledge moves in one direction (a flow must be InputStream perhaps OutputStream And channels can be used for reading, writing, or both.
	because CHannel It is double full-service, so it better maps the underlying operating system than stream API. Especially in UNIX In the network programming model, the underlying operating systems are full duplex and support read-write operations at the same time.
	Channel It can be divided into two categories: for network reading and writing SelectableChannel And for file operations FileChannel. ServerSocket and SocketChannel All SelectableChannel Subclass of.

3. Multiplexer Selector

	The multiplexer provides the ability to select tasks that are ready. In short, Selector It will register on it continuously Channel,If one Channel There are read or write events on it. This Channel Will be ready and will be Selector Poll out

4. Examples of NiO client and NIO server

public class NioClient {
    public static void client() throws IOException {
        // Get channel
        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
        FileChannel inChannel = FileChannel.open(Paths.get("C:\\Users\\renyun\\Desktop\\picture\\logo2.png"), StandardOpenOption.READ);
        // Allocates a buffer of the specified size
        ByteBuffer buf = ByteBuffer.allocate(1024);
        // Read the local file and send it to the server
        while (inChannel.read(buf) != -1) {
            // Switch to read data mode
            buf.flip();
            // Writes data from the buffer to the pipeline
            sChannel.write(buf);
            // Empty buffer
            buf.clear();
        }

        //Close channel
        inChannel.close();
        sChannel.close();
    }
    public static void main(String[] args) {
        new Thread(() -> {
            try {
                server();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }, "t1").start();
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            try {
                client();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }, "t2").start();
    }
}
public class NioServer {
    /**
     * Server
     */
    public static void server() throws IOException {
        // Get channel
        ServerSocketChannel ssChannel = ServerSocketChannel.open();
        FileChannel fileChannel = FileChannel.open(Paths.get("C:\\Users\\renyun\\Desktop\\picture\\logo2.png"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        // Binding port number
        ssChannel.bind(new InetSocketAddress(9898));
        // Get the channel of client connection
        SocketChannel socketChannel = ssChannel.accept();
        // Allocates a buffer of the specified size
        ByteBuffer buf = ByteBuffer.allocate(1024);
        // Read the data of the client and save it locally
        while(socketChannel.read(buf) != -1) {
            // Switch to read mode
            buf.flip();
            // write in
            fileChannel.write(buf);
            // Empty buffer
            buf.clear();
        }
        // Close channel
        ssChannel.close();
        socketChannel.close();
        fileChannel.close();
    }

}

5 why not choose native NIO programming

1.NIO's class libraries and API s are complicated and troublesome to use
2. You need to have other additional skills, such as being familiar with multithreading programming. NIO involves Reactor mode, so you must be very familiar with multithreading and network programming.
3. I can't afford to be happy. The workload and difficulty are very large
4. There is a bug in JDK NiO

2 Netty NIO Getting Started Guide

There are two versions of Netty4 and Netty. It's best to choose Netty4. The first step is to build the project. You can directly reference Maven's dependent package, or directly uninstall the jar package and copy it to the lib directory.

<!--netty rely on-->
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.1.20.Final</version>
    </dependency>
  </dependencies>

2.1 netty entry server development

public class NettyServer {
    public static void main(String[] args) throws InterruptedException {

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        try {
            bootstrap.group(bossGroup, worker)  //Set up two thread groups
                    .channel(NioServerSocketChannel.class)  //Channel implementation as a server
                    .option(ChannelOption.SO_BACKLOG,128) //Set the number of thread queues waiting for connections
                    .childOption(ChannelOption.SO_KEEPALIVE,true) //Set keep active connection status
                    .childHandler(new ChannelInitializer<SocketChannel>() { //Create a channel initialization object
                        //Set up the processor for pipline
                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            channel.pipeline().addLast(new NettyServerHandler());

                        }

                    });  //
            System.out.println("The server is ready");
            //Bind a port and synchronize it to generate a ChannelFuture object

            ChannelFuture cf = bootstrap.bind(6668).sync();

            //Listen for closed channels asynchronous model channelFuture
            cf.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            worker.shutdownGracefully();
        }



    }
}

Introduce key classes
NioEventLoopGroup is specially used for processing network events. In fact, it is the reactor thread group. Two reasons are created: one is for the server to accept the connection of the client, and the other is for the network reading and writing of SocketChannel.
ServerBootstrap is an auxiliary startup class used by Netty to start the server. In order to reduce the development complexity of the server, call the group method and pass the two thread groups to ServerBootstrap as input parameters
ServerSocketChannel class in JDK NIO class library corresponding to NioServerSocketChannel

public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    //Read data actual (read client message) ChannelHandlerContext context object
    // The message sent by the Object msg client is in the form of object by default
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("server ctx ="+ctx);
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("Send message to client"+buf.toString(CharsetUtil.UTF_8));
        System.out.println("Client address"+ctx.channel().remoteAddress());
//        super.channelRead(ctx, msg);
        //Convert msg to bytebuffer
    }
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello client",CharsetUtil.UTF_8));

    }
    //Handle exceptions, usually by closing the channel
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
//        super.exceptionCaught(ctx, cause);
    }
}

NettyServerHandler inherits from ChannelInboundHandlerAdapter and reads and writes network events;
Focus on channelRead and exceptionguess methods.
ByteBuf buf = (ByteBuf) msg; Convert msg to Netty's bytebuf object. The bytebuf method can get the number of bytes of the buffer
As can be seen from the above code, compared with the service side of the traditional JDK NIO native class library, the amount of code and development are greatly reduced.

2.2 netty client development

public class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        //The client needs only one event loop group
        EventLoopGroup eventExecutors = new NioEventLoopGroup();

        try{
            //Create client startup object
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventExecutors)
                    .channel(NioSocketChannel.class) //Set the processing of client channel
                    .handler(new ChannelInitializer<SocketChannel>() { //Create a channel initialization object
                        //Set up the processor for pipline
                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            channel.pipeline().addLast(new NettyClientHandler());

                        }

                    });
            System.out.println("The client is ready");
            ChannelFuture cf = bootstrap.connect("127.0.0.1", 6668).sync();
            cf.channel().closeFuture().sync();
        }finally {
            eventExecutors.shutdownGracefully();
        }
    }
}
public class NettyClientHandler extends ChannelInboundHandlerAdapter {

    //This method is triggered when the channel is ready
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client" +ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("HELLO SERVER", CharsetUtil.UTF_8));
    }

    //Triggered when the channel has a read event
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("Messages replied by the server"+buf.toString(CharsetUtil.UTF_8));
        System.out.println("Server side address"+ctx.channel().remoteAddress());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {


        cause.printStackTrace();
        ctx.close();
    }
}

The service of the client is simpler than that of the server;

Commissioning and operation



It should be noted that this routine does not consider the processing of reading half package, and there is no problem with function demonstration or test. However, if the stress test is carried out, it will not work normally, and the knowledge points related to half package need to be processed. Some methods are used to solve TCP packet sticking and unpacking.

Keywords: Java Netty network

Added by slyte33 on Thu, 03 Feb 2022 16:26:06 +0200