每天10分钟学习Netty——基础入门1:Hello,NettyServer
凡是新知识都需要有个入门的案例,一个简单的输入输出就能解除你当前遇到的所有疑惑。直接上手,直接撸代码,理论先丢在一边。
今天的学习内容是:
- 用Netty实现一个服务端
- 用NetAssist工具模仿客户端连接这个服务端。
package com.lcy.exercise.netty.y2025;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyServer {
public static void main(String[] args) {
new NettyServer().bing(6677);
}
private void bing(int port) {
//配置服务端NIO线程组
EventLoopGroup parentGroup = new NioEventLoopGroup(); //NioEventLoopGroup extends MultithreadEventLoopGroup Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
EventLoopGroup childGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(parentGroup, childGroup)
.channel(NioServerSocketChannel.class) //非阻塞模式
.option(ChannelOption.SO_BACKLOG, 128)
.childHandler(new MyChannelInitializer());
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
childGroup.shutdownGracefully();
parentGroup.shutdownGracefully();
}
}
}
package com.lcy.exercise.netty.y2025;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
public class MyChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel channel) {
System.out.println("链接报告开始");
System.out.println("链接报告信息:有一客户端链接到本服务端");
System.out.println("链接报告IP:" + channel.localAddress().getHostString());
System.out.println("链接报告Port:" + channel.localAddress().getPort());
System.out.println("链接报告完毕");
}
}
这两段代码实现了一个基于Netty框架的简单服务器。下面是对这两个类的具体解释:
NettyServer 类
NettyServer
是一个简单的Netty服务器实现,它监听特定端口等待客户端连接,并为每个新连接初始化通道(Channel)处理器。
-
主方法 (
main
):- 创建
NettyServer
实例并调用bing
方法,传入端口号6677作为参数。
- 创建
-
bing
方法:- 创建两个
EventLoopGroup
对象:parentGroup
和childGroup
。前者负责处理服务器端接受连接,后者负责处理已建立连接的数据读写等操作。 - 使用
ServerBootstrap
来配置服务器:- 调用
group()
方法指定线程池。 - 使用
channel()
方法设置使用的Channel类型为NioServerSocketChannel
,表示非阻塞模式下的服务端套接字。 - 设置一些选项,如
SO_BACKLOG
,用于指定当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最大长度。 - 指定子通道的处理器通过
childHandler()
方法,这里指定了自定义的MyChannelInitializer
处理器。
- 调用
- 调用
bind()
方法绑定到指定端口,并同步等待直到绑定完成。 - 最后,调用
closeFuture().sync()
等待通道关闭,这将使主线程在此处阻塞,直到服务器通道被关闭。 - 在
finally
块中确保无论发生什么情况都会优雅地关闭线程池。
- 创建两个
MyChannelInitializer 类
MyChannelInitializer
继承自 ChannelInitializer<SocketChannel>
,这是一个辅助类,用来在新连接建立时向 ChannelPipeline 中添加必要的处理器。
initChannel
方法:- 当一个新的客户端连接到服务器时,这个方法会被调用。
- 它打印出一些链接报告信息,包括客户端连接到的服务端IP地址和端口号。
- 注意,这里的输出是针对服务端自身的本地地址和端口,而不是客户端的地址和端口。如果要获取客户端的信息,应该使用
channel.remoteAddress()
。
实操
- 启动Server端
- 使用NetAssist模拟客户端,连接我们编写的Server端
- 查看控制台日志
总结
这段代码展示了如何创建一个基本的Netty服务器,该服务器监听6677端口,并为每个新的客户端连接打印一条消息。实际的应用程序通常会在 MyChannelInitializer
中添加更多的处理器来处理业务逻辑,比如编码解码器、业务逻辑处理器等。此外,目前的链接报告信息只是简单的标准输出,实际项目中可能会记录日志或发送通知。