什么是Netty
简单概括,Netty是一个Java开源框架,是一个异步的、基于事件驱动的网络应用框架,用以快速开发高性能、高可靠的网络IO程序。Netty 本质是一个 NIO 框架,适用于服务器通讯相关的多种应用场景。
准备
能够很好的理解这个project,最好对SpringBoot、Netty、长连接及im即时通讯有相关的提前了解。
目录结构及源码
项目源码:github项目源码,有任何问题也欢迎交流讨论
项目基于gradle,目录如下
- api:Netty服务端
- client:Netty客户端
- logic:业务逻辑,提供Netty的基础封装,api与client复用
服务端启动类:NettyImDemoApiApplicationContext
客户端启动类:NettyImDemoClientApplicationContext
Netty服务端构建
Netty服务端两个核心类:
NettyServer服务端引导类
public class NettyServer {
/**
* 读取application.yml配置
*/
@Value("${netty.port}")
private Integer port;
/**
* Netty Server服务端Channel
*/
private Channel channel;
private EventLoopGroup bossGroup = new NioEventLoopGroup();
private EventLoopGroup workerGroup = new NioEventLoopGroup();
private final NettyServerHandlerInitializer nettyServerHandlerInitializer;
public NettyServer(NettyServerHandlerInitializer nettyServerHandlerInitializer) {
this.nettyServerHandlerInitializer = nettyServerHandlerInitializer;
}
/**
* 启动Netty Server
* @throws InterruptedException
*/
@PostConstruct
public void start() throws InterruptedException {
// 创建引导,用于netty启动
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 在创建ServerBootstrap类实例前,先创建两个EventLoopGroup,它们实际上是两个独立的Reactor线程池
// Netty默认线程模型是「主从Reactor多线程模型」,
serverBootstrap.group(bossGroup, workerGroup)
// 指定 Channel为服务端NioServerSocketChannel
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
// 设置服务端accept队列大小
.option(ChannelOption.SO_BACKLOG, 1024)
// TCP Keepalive 机制,实现 TCP 层级的心跳保活功能
.childOption(ChannelOption.SO_KEEPALIVE, true)
// 允许较小的数据包的发送,降低延迟
.childOption(ChannelOption.TCP_NODELAY, true)
// 设置客户端连接上来的 Channel 的处理器为 NettyServerHandlerInitializer
// 在每一个客户端与服务端建立完成连接时,服务端会创建一个Channel与之对应, NettyServerHandlerInitializer会进行执行initChannel(Channel c) 方法,进行自定义的初始化
.childHandler(nettyServerHandlerInitializer);
// 绑定端口,并同步等待成功,即启动Netty Server服务端
ChannelFuture future = serverBootstrap.bind().sync();
if (future.isSuccess()) {
// 启动成功,获取Channel引用
channel = future.channel();
log.info("start Netty Server port {}", port);
}
}
/**
* 关闭 Netty Server
*/
@PreDestroy
public void gracefulShutdown() {
if (Objects.nonNull(channel)) {