Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
Netty, Netty, Netty, Netty, Netty, Netty, Netty
I originally intended to write the theoretical knowledge first, but on second thought, I decided that I should write the code first, and then use the code and flow chart to better analyze the components and mechanisms in Netty.
So let’s write our first Netty application.
I. Programming steps:
- Set up a Maven project.
- Import dependence
- Write the Netty server
- Write a ChannelHandler (which the server uses to process data received from the client) and business logic
- Write a Server startup class
- Write a Netty client
- Write a ChannelHadler to handle the client logic
- Boot client
- Finally start the test (punch off 😁)
Two, import dependency:
If you don’t want to import netty-all, you can import whatever you want, because netty supports a wide range of Jar packages.
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.65. The Final</version>
</dependency>
Copy the code
Three, write the server side:
Start with ServerHandler, which handles business logic.
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/ * * *@Author: crush
* @Date: 2021-08-22 10:19
* version 1.0
* @deprecated @SharableIndicates that the same instance of an annotated ChannelHandler can be added to one or more Channel pipelines multiple times without race conditions. * /
@ChannelHandler.Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
/** ** is called for each incoming message
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf) msg;
// Log the message to the console
System.out.println(
"Server received: " + in.toString(CharsetUtil.UTF_8));
// Write the received message to the sender without flushing the outbound message
ctx.write(in);
}
/** * -- notifying ChannelInboundHandler that the last call to channelRead() was the last message in the current batch read */
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
// Send the message to the remote node and close the Channel
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
.addListener(ChannelFutureListener.CLOSE);
}
/** ** is called when an exception is thrown during a read operation
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); }}Copy the code
Server side startup class:
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public static void main(String[] args) throws Exception {
int port=8081;
new EchoServer(port).start();
}
public void start(a) throws Exception {
final EchoServerHandler serverHandler = new EchoServerHandler();
/ / create EventLoopGroup
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// It allows easy booting of ServerChannel
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup,workerGroup)
/** The Class from which to create a Channel instance */
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
// Add an EchoServerHandler to the sub-channel's ChannelPipeline
.childHandler(new ChannelInitializer<SocketChannel>() {
// Process I/O events or intercept I/O operations and forward them to the next handler on their ChannelPipeline
@Override
public void initChannel(SocketChannel ch)
throws Exception {
//EchoServerHandler is labeled @shareable, so we can always use the same instancech.pipeline().addLast(serverHandler); }});/** * bind the server asynchronously; Call sync() to block and wait until the binding is complete */
ChannelFuture f = b.bind().sync();
/** * gets the CloseFuture of the Channel and blocks the current thread until it finishes */
f.channel().closeFuture().sync();
} finally{ bossGroup.shutdownGracefully().sync(); workerGroup.shutdownGracefully(); }}}Copy the code
Four, write the client:
EchoClientHandler
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;
import java.util.Scanner;
@ChannelHandler.Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
/** * will be called after the connection to the server has been established; * /
@Override
public void channelActive(ChannelHandlerContext ctx) {
// Send a message when notified that a Channel is active
ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks! Hello ya!!" ,
CharsetUtil.UTF_8));
}
/** * called when a message is received from the server; * /
@Override
public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) {
// Records the dump of received messages
System.out.println(
"Client received: " + in.toString(CharsetUtil.UTF_8));
}
/** * is called when an exception is thrown during processing. * /
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); }}Copy the code
EchoClient
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.net.InetSocketAddress;
public class EchoClient {
private final String host;
private final int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start(a) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
// Specify EventLoopGroup to handle client events; Needs to be applicable to NIO implementations
b.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
When creating a Channel, add an EchoClientHandler instance to the ChannelPipeline
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(
newEchoClientHandler()); }}); ChannelFuture f = b.connect().sync(); f.channel().closeFuture().sync(); }finally{ group.shutdownGracefully().sync(); }}public static void main(String[] args) throws Exception {
String host="localhost";
int port=8081;
newEchoClient(host, port).start(); }}Copy the code
Five, the test
Start the server first
Restart the client:
Six, the concluding
After reading this chapter, if this is your first encounter, you will definitely be confused.
So what I want you to do is I want you to look at the code, and then I want you to draw a flow chart, and then I want you to analyze it.
This article continues to be updated, and more tomorrow.
So for more information about Netty workflows and core components 👈 (👨💻)