Play with Netty, start with "Hello World"!
Play with Netty, start with "Hello World"!
Hello everyone, I am the third child. Previously, we discussed the three IO models of Java and mentioned the network communication framework Netty, which simplifies and optimizes the use of NIO. In this issue, we officially start to approach Netty.
Why use Netty?
First of all, of course, the use of NIO is relatively complicated and there are still some problems.
In addition, if you want to achieve stable network communication during project development, you have to consider network interruptions, repeated client access, client security authentication, message encoding and decoding, half-packet reading and writing...
So, by coincidence, there happens to be such a mature, stable, powerful, and out-of-the-box network framework in front of us. Compared with Java NIO, Netty is even better:
- Ease of use: Netty implements a higher level of encapsulation based on NIO, shielding the complexity of NIO and greatly reducing the difficulty of development; Netty provides many out-of-the-box tools, such as commonly used line decoders and length fields. Decoders, etc., do not need to be implemented by yourself.
- Stability: Netty is more reliable and stable, and has fixed and improved many known problems of JDK NIO, such as the notorious select idling causing 100% CPU consumption, TCP disconnection and reconnection, keep-alive detection and other issues.
- Scalability: Netty's scalability is very good, such as supporting customizable threading models.
What reason do we have to reject such an excellent network communication framework? How to write code is not about writing!
First introduction to Netty
What is Netty?
Netty officially defines Netty like this:
Netty is an asynchronous event-driven network application framework for rapid development of maintainable, high-performance protocol servers and clients.
Composition diagram-Official source
- Netty is an open source, single-threaded model Java network programming framework.
- Netty is based on NIO and is widely used in various network application development.
- Netty supports multiple protocols, including but not limited to HTTP, WebSocket, TCP, UDP and SSL/TLS protocols.
- Netty is a non-blocking, event-driven framework.
- Netty has the advantages of high performance, scalability and ease of use.
Netty’s current situation?
Netty is developed and maintained by the JBoss community, and its community is relatively active:
- https://github.com/netty/netty: Github has received 31.2K stars
- https://netty.io/: Official website, providing relatively complete documentation
The latest official version is 5.x, but unfortunately, it has been abandoned by the community for development and maintenance and is an abandoned version. The latest stable version is 4.x.
For general use, 4.x is recommended. Netty 4.x is not compatible with 3.x. Our subsequent learning is also based on Netty 4.x version.
Who is using Netty?
As the most popular network communication framework, a large number of companies choose it as the underlying network communication framework, including but not limited to:
Companies using Netty
We may not have used Netty directly, but in fact many open source middleware we are familiar with use Netty, such as:
- Service governance: Apache Dubbo, gRPC.
- Big data: Hbase, Spark, Flink, Storm.
- Search engine: Elasticsearch.
- Message queue: RocketMQ, ActiveMQ.
There are many excellent products that use Netty. If you are interested, you can take a look: https://netty.io/wiki/related-projects.html.
Start with "Hello World"
The atmosphere is so high that I can't get through it without writing a demo. Let's start with "Hello World" to get a taste of Netty's style.
- Create a Maven project: Needless to say more about this
Create a Maven project
- Import dependencies: We directly use the latest version 4.x
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.92.Final</version>
</dependency>
- 1.
- 2.
- 3.
- 4.
- 5.
- Write code: Then we start writing the server and client related code of this Demo
- NettyServer: Netty-based client
/**
* <p>Date: 2023/5/14 10:29</p>
* <p>Author: fighter3</p>
* <p>Description: Netty服务端Demo</p>
*/
public class NettyServer{
// 服务器监听的端口号
private int port;
public NettyServer(int port) {
this.port = port;
}
/**
* 启动Netty服务器
* @throws InterruptedException
*/
public void run() throws InterruptedException {
// 创建boss线程组和worker线程组
// bossGroup 用于监听客户端的连接请求,将连接请求发送给 workerGroup 进行处理
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
// workerGroup 用于处理客户端连接的数据读写
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 创建 ServerBootstrap 对象,用于启动 Netty 服务器
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 绑定线程池事件组
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
// 通道初始化回调函数,在启动的时候可以自动调用
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加消息处理器
pipeline.addLast(new NettyServerHandler());
}
});
// 绑定端口,开始接收客户端请求
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
System.out.println("Netty服务器监听端口:"+port);
// 等待服务端监听端口关闭
channelFuture.channel().closeFuture().sync();
} finally {
//释放线程组资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
// 创建服务器对象,监听端口号为 8888
NettyServer server = new NettyServer(8888);
System.out.println("============Netty服务器启动...=============");
// 启动服务器
server.run();
System.out.println("============Netty服务器停止...=============");
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- NettyServerHandler: The server's message processor, used to handle various events
/**
* <p>Date: 2023/5/14 10:30</p>
* <p>Author: fighter3</p>
* <p>Description: Netty服务器消息处理器</p>
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
/**
* 当客户端上线的时候会触发这个方法
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String message="你好,靓仔!";
ByteBuf hello = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8);
// 发送消息
ctx.writeAndFlush(hello);
}
/**
*当 Channel 中有来自客户端的数据时就会触发这个方法
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("客户端发来的消息:" + buf.toString(CharsetUtil.UTF_8)); // 接收消息并打印输出
}
/**
* 当有异常时触发这个方法
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- NettyClient: Use Netty client to connect to the server through ip and port
/**
* <p>Date: 2023/5/14 10:32</p>
* <p>Author: fighter3</p>
* <p>Description: Netty客户端Demo</p>
*/
public class NettyClient {
// 服务器 IP
private String host;
// 服务器监听的端口号
private int port;
public NettyClient(String host, int port) {
this.host = host;
this.port = port;
}
/**
* 启动 Netty 客户端
*/
public void run() throws InterruptedException {
// 创建事件循环组
NioEventLoopGroup group = new NioEventLoopGroup();
try {
// 创建 Bootstrap 对象
Bootstrap bootstrap = new Bootstrap();
// 配置 Bootstrap 对象
// 设置线程组
bootstrap.group(group)
// 设置客户端通信的通道类型为NIO类型
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
// 通道初始化回调函数,在启动的时候可以自动调用
@Override
public void initChannel(SocketChannel ch) throws Exception {
// 添加消息处理器
ch.pipeline().addLast(new NettyClientHandler());
}
});
// 连接服务器,异步等待连接成功
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
System.out.println("===========Netty客户端连接服务端=========");
// 等待客户端连接关闭
channelFuture.channel().closeFuture().sync();
} finally {
//释放资源
group.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
// 创建客户端对象,并连接到服务器
NettyClient client = new NettyClient("127.0.0.1", 8888);
// 启动客户端,开始发送消息
client.run();
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- NettyClientHandler: Netty client handler, used to handle various events
/**
* <p>Date: 2023/5/14 10:33</p>
* <p>Author: fighter3</p>
* <p>Description: Netty客户端处理器</p>
*/
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
/**
* 当 Channel 准备就绪时就会触发这个方法
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String message="大佬,带带我!";
ByteBuf hello = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8);
// 发送消息
ctx.writeAndFlush(hello);
}
/**
* 当 Channel 中有来自服务器的数据时就会触发这个方法
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("服务端发来的消息:" + buf.toString(CharsetUtil.UTF_8)); // 接收消息并打印输出
}
/**
* 发生异常就会触发这个方法
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- Run it: Start NettyServer first, then NettyClient, and see the results.
============Netty服务器启动...=============
Netty服务器监听端口:8888
客户端发来的消息:大佬,带带我!
- 1.
- 2.
- 3.
===========Netty客户端连接服务端=========
服务端发来的消息:你好,靓仔!
- 1.
- 2.
Okay, a simple Netty introductory demo has been written. Netty is a network framework for duplex communication. It can be seen that the process of the server and the client is basically the same, mainly including the following steps:
- Create event loop groups and related objects for monitoring and processing network events;
- Configure the startup parameters of the Netty server or client, including thread group, channel type, TCP parameters, etc.;
- Add various ChannelHandlers to the server or client's ChannelPipeline to handle different network events;
- Bind the port to start the server or connect to the server;
- Wait for the server or client connection to be closed and release related resources.
Server & client initialization startup process
Although this Demo is relatively simple, it actually uses several key components in Netty:
- ByteBuf: Netty's byte container, similar to Java's ByteBuffer, but provides a more powerful, simple and secure API for transmitting binary data over the network;
- EventLoopGroup: Netty's event loop group, used to manage and schedule event loops on all Channels connected to or from the server;
- ServerBootstrap: Netty's server startup class, used to start and configure a TCP/IP server;
- Bootstrap: Netty's client startup class, used to start and configure a TCP/IP client;
- Channel: The core concept of Netty, used to represent a communication channel that can read and write data;
- ChannelPipeline: Netty's Channel processor, used to execute a set of ChannelHandlers on incoming data;
- ChannelHandler: The core component of Netty, used to handle various communication events, such as reading data, writing data, establishing connections, etc.;
Important components of Netty
We will have more to do with these components in the future.
Okay, that’s it for this issue. In this issue, we have a preliminary understanding of Netty, including what is Netty, the current situation of Netty, the application of Netty, and also wrote a simple Demo. In the next issue, we will continue to learn more about Netty, so stay tuned.