Netty

(Reference: Netty Tutorial)

1. About the Netty

1.1 the concept:

Netty is a client/server programming framework based on NIO. Using Netty, you can quickly and easily develop a network application, such as a client/server application that implements a certain protocol.

1.2 advantage:

A. High concurrency B. fast transmission C. Good encapsulation

Principle 2.

2.1 About BIO and NIO:

Basic concept understanding:

Synchronization: Synchronization is when a call is made and does not return until the caller has processed the request

Asynchrony: Asynchrony means that after making a call, we immediately get the response from the called to indicate that the request has been received, but the called does not return the result. At this time, we can process other requests. The called usually relies on events, callbacks and other mechanisms to notify the caller of the return result

Block: A block is when a request is made and the caller waits for the result of the request to return, meaning that the current thread is suspended and cannot continue until the condition is ready

Non-blocking: Non-blocking is making a request so the caller doesn’t have to wait for the result to come back and can do something else first

BIO: Synchronous blocking IO, that is, data reads and writes must block in a thread waiting for it to complete

BIO here:

BIO communication model diagram:

For a server that uses the BIO communication model, a separate Acceptor thread is usually responsible for listening for client connections. In the while(true) loop, the server will call accept() method to wait for the client to receive the connection request. Once the request receives a connection request, it can establish a communication socket and perform read and write operations on this communication socket. At this time, it cannot receive other client connection requests. You can only wait for the currently connected client to complete, but you can support multiple client connections through multithreading

NIO: Synchronizes non-blocking I/OS. It blocks service processing but does not block data receiving. NIO is suitable for scenarios with high concurrency and simple processing, such as chat software

NIO here:

NIO communication model diagram:

When a connection is established, it has two steps to do. The first step is to receive all the data sent by the client, and the second step is to return the response to the client after processing the request. The main difference between NIO and BIO is in the first step. In the BIO, waiting for the client to send data is blocked, resulting in a situation in which only one request can be processed per thread, and the maximum number of threads the machine can support is limited, which is why the BIO does not support high concurrency. In NIO, when a Socket is established, the Thread does not block to accept the Socket. Instead, it sends the request to the Selector. The Selector iterates through all the sockets, notifies the Thread when a Socket is established. The Thread then processes the data and returns it to the client — this process is non-blocking, allowing one Thread to process more requests.

The characteristics of Netty

High concurrency: Based on the JDK NIO, non-blocking, one thread can process multiple socket connections, so as to support high concurrency

Fast transmission: Generally, if our data needs to be read from IO to heap memory, it needs to pass through Socket buffer in the middle, that is to say, a data will be copied twice before reaching its destination. If there is a large amount of data, it will cause unnecessary resource waste. Netty aimed at this situation, use the another big characteristic of NIO – zero copy, when he needs to receive the data, he will set up a block of memory outside heap memory, the data is read from the IO directly to that piece of memory, in Netty through ByteBuf can directly manipulate these data directly, thus speeding up the transmission speed.

Good encapsulation: it contains a lot of encapsulated APIS, easy to use, less coding.

Netty execution process

As shown in figure:

The core components of Netty

Channel

A Channel is a basic construct of Java NIO. Can be regarded as a carrier of incoming or outgoing data. Therefore, it can be turned on or off, connected or disconnected

EventLoop and EventLoopGroup

EventLoop defines Netty’s core abstraction for handling events that occur during the lifetime of a connection. Internally, an EventLoop is assigned to each Channel.

An EventLoopGroup is a pool of eventloops that contains many eventloops. Netty assigns an EventLoop to each Channel, which handles all events such as user connection requests and processing of user requests. EventLoop itself is just a thread-driver that binds only one thread to handle all I/O events for a Channel during its lifetime.

Once a Channel is bound to an EventLoop, it cannot be changed for the lifetime of the Channel. An EventLoop can bind to multiple channels. That is, the relationship between Channel and EventLoop is N :1, while the relationship between EventLoop and thread is 1:1

ServerBootstrap with the Bootstrap

Bootstarp and ServerBootstrap, called bootstrap classes, refer to the process of configuring an application and getting it running. Netty handles boot by isolating your application from the network layer.

Bootstrap is the client Bootstrap class. When calling bind(UDP) and connect(TCP), Bootstrap creates a new Channel. Just create a single Channel with no parent Channel to implement all network exchanges.

ServerBootstrap is the bootstrap class on the server side. ServerBootstarp creates a ServerChannel when calling bind() to accept the connection from the client. And the ServerChannel manages multiple subchannels for communication with clients

ChannelHandler and ChannelPipeline

Channelhandlers are the handlers for the data in a Channel. These handlers can be either system-defined codecs or user-defined ones. These handlers are added to a ChannelPipeline object, and the data in the Channel is processed in the order they are added

ChannelFuture

All I/O operations in Netty are asynchronous, that is, operations do not return results immediately. Therefore, Netty defines a ChannelFuture object to represent the asynchronous operation. If you want to get the return value of the asynchronous operation, you can add the NIO Netty listener to the asynchronous operation by using the addListener() method of the asynchronous operation object, register the callback for the asynchronous operation: call the callback immediately after the result comes out.

Netty’s asynchronous programming model is built on the concepts of futures and callbacks

Start using Netty

Netty-Server

Netty-server configuration code:

public class NettyServer { public static void main(String[] args) throws InterruptedException { EventLoopGroup parentGroup = new NioEventLoopGroup(); EventLoopGroup childGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(parentGroup, childGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new StringDecoder()); pipeline.addLast(new StringEncoder()); pipeline.addLast(new SomeSocketServerHandler()); }}); ChannelFuture future = bootstrap.bind(8888).sync(); System.out.println(" Server started... ") ); future.channel().closeFuture().sync(); } finally { parentGroup.shutdownGracefully(); childGroup.shutdownGracefully(); }}}Copy the code

Server-side handler code:

public class DemoSocketServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("Client Address ====== " + ctx.channel().remoteAddress()); ctx.channel().writeAndFlush("from server:" + UUID.randomUUID()); ctx.fireChannelActive(); TimeUnit.MILLISECONDS.sleep(500); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}Copy the code

Netty-Client

Netty-client configuration code:

public class NettyClient { public static void main(String[] args) throws InterruptedException { NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(eventLoopGroup) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast(new DemoSocketClientHandler()); }}); ChannelFuture future = bootstrap.connect("localhost", 8888).sync(); future.channel().closeFuture().sync(); } finally { if(eventLoopGroup ! = null) { eventLoopGroup.shutdownGracefully(); }}}}Copy the code

client-handler:

public class DemoSocketClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println(msg); ctx.channel().writeAndFlush("from client: " + System.currentTimeMillis()); TimeUnit.MILLISECONDS.sleep(5000); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.channel().writeAndFlush("from Client: the begin talking "); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}Copy the code