1. 引入 Maven 依赖
在 pom.xml 中加入 Netty 依赖:
XML
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.94.Final</version> <!-- 建议使用较新的稳定版本 -->
</dependency>
2. 编写服务端代码 (Server)
Netty 的核心逻辑在于 ChannelInitializer,可以在这里定义处理流程(Pipeline)。
java
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
// 1. 创建两个线程组
// bossGroup: 专门负责接收客户端连接
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// workerGroup: 专门负责处理已连接通道的读写事件
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // 使用 NIO 模式
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
// 2. 配置 Pipeline (数据处理流水线)
ChannelPipeline p = ch.pipeline();
p.addLast(new StringDecoder()); // 自动将接收到的字节转为 String
p.addLast(new StringEncoder()); // 自动将 String 转为字节发送
p.addLast(new SimpleChannelInboundHandler<String>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
System.out.println("收到消息: " + msg);
ctx.writeAndFlush("服务端已收到:" + msg); // 回复消息
}
});
}
});
// 3. 绑定端口,启动服务
ChannelFuture f = b.bind(8080).sync();
System.out.println("服务器启动,监听 8080 端口...");
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
3. 代码核心组件解析
如果想真正"会用" Netty,这 4 个组件是必须理解的:
- EventLoopGroup(线程模型) :
- 这就是前面提到的 Reactor 模型。Boss 负责接客,Worker 负责干活。可以简单理解为管理线程的"包工头"。
- ChannelInitializer(流水线工厂) :
- 每一个连接建立后,都会执行
initChannel。在这里添加Handler,就像是给工厂流水线安装不同的处理设备(编码器、解码器、业务逻辑处理器)。
- 每一个连接建立后,都会执行
- ChannelPipeline(责任链) :
- 所有的
Handler串在一起组成 Pipeline。数据像水流一样经过每一个 Handler。比如:字节 -> 解码器 -> 业务处理 -> 编码器 -> 字节。
- 所有的
- ChannelHandler(业务逻辑) :
- 写的业务代码都在这里。例如
channelRead处理数据输入,exceptionCaught处理异常。
- 写的业务代码都在这里。例如
4. 为什么要这样用?
- 非阻塞 :上面的
NioEventLoopGroup确保了即使有成千上万个连接,服务器依然不会因为一个连接处理慢而卡住其他连接。 - 模块化 :想支持加密?在 Pipeline 里加一个
SslHandler即可。想支持心跳检测?加一个IdleStateHandler即可。完全不需要改动的业务逻辑代码。
进阶建议:
- 不要在 Handler 中做耗时操作 :Netty 的 EventLoop 线程非常宝贵,如果的业务逻辑(如查数据库)很慢,必须使用 Netty 提供的
EventExecutorGroup将任务异步化,否则会把整个 Netty 线程池卡死。 - 粘包/拆包处理 :在真实生产环境,TCP 会发生"粘包"(两条消息连在一起)或"拆包"(一条消息断成两截)。不要直接用
StringDecoder,生产环境通常使用LengthFieldBasedFrameDecoder(基于长度的帧解码器)来切割数据。
可以试着运行上面的代码,然后用 telnet localhost 8080 / nc localhost 8080 在终端连接它发几条消息试试。