Netty基础服务器实现

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 个组件是必须理解的:

  1. EventLoopGroup(线程模型) :
    • 这就是前面提到的 Reactor 模型。Boss 负责接客,Worker 负责干活。可以简单理解为管理线程的"包工头"。
  2. ChannelInitializer(流水线工厂) :
    • 每一个连接建立后,都会执行 initChannel。在这里添加 Handler,就像是给工厂流水线安装不同的处理设备(编码器、解码器、业务逻辑处理器)。
  3. ChannelPipeline(责任链) :
    • 所有的 Handler 串在一起组成 Pipeline。数据像水流一样经过每一个 Handler。比如:字节 -> 解码器 -> 业务处理 -> 编码器 -> 字节。
  4. ChannelHandler(业务逻辑) :
    • 写的业务代码都在这里。例如 channelRead 处理数据输入,exceptionCaught 处理异常。

4. 为什么要这样用?

  • 非阻塞 :上面的 NioEventLoopGroup 确保了即使有成千上万个连接,服务器依然不会因为一个连接处理慢而卡住其他连接。
  • 模块化 :想支持加密?在 Pipeline 里加一个 SslHandler 即可。想支持心跳检测?加一个 IdleStateHandler 即可。完全不需要改动的业务逻辑代码。

进阶建议:

  • 不要在 Handler 中做耗时操作 :Netty 的 EventLoop 线程非常宝贵,如果的业务逻辑(如查数据库)很慢,必须使用 Netty 提供的 EventExecutorGroup 将任务异步化,否则会把整个 Netty 线程池卡死。
  • 粘包/拆包处理 :在真实生产环境,TCP 会发生"粘包"(两条消息连在一起)或"拆包"(一条消息断成两截)。不要直接用 StringDecoder,生产环境通常使用 LengthFieldBasedFrameDecoder(基于长度的帧解码器)来切割数据。

可以试着运行上面的代码,然后用 telnet localhost 8080 / nc localhost 8080 在终端连接它发几条消息试试。

相关推荐
程序猿乐锅2 分钟前
万字详解Single-flight(单飞模式)
java·开发语言·分布式·后端·学习·single-flight
Java后端的Ai之路14 分钟前
【AIAgent开发】-Agent工具封装成CLI(纯干货!!!)
java·javascript·人工智能·agent·cli
AntsData43 分钟前
用 12K+ 条亚马逊评论信号,定位机械键盘下一版该改什么
java·大数据·计算机外设
code2cat1 小时前
【随笔】连续批处理:长短请求怎样在迭代之间补位
java·人工智能·后端·大语言模型·vllm
最强小杰1 小时前
DeepSeek V4 Flash + Codex CLI 接入教程:原生 Responses API 适配,从配置到跑通收藏这篇就够了(2026)
java·前端·python·ai
Flynn Liang1 小时前
Spring AI 2.0 深度解析:ChatClient、Advisor 链与 MCP——Java 工程师的 AI 落地最优解
java·人工智能·spring·大模型·架构设计·spring ai
灿飞1 小时前
Kotlin与Java虚拟机六:基础与类型系统:一切皆对象,但对象有代价
java·kotlin
计算机毕设定制辅导-无忧学长1 小时前
《基于微信小程序健康习惯激励系统设计与实现》
java·spring boot·mysql·微信小程序·uniapp·健康习惯激励系统
雪芽蓝域zzs2 小时前
第 1 章:IDEA 创建 SpringBoot3.5.16 Maven 项目
java·maven·intellij-idea
golang学习记2 小时前
IDEA 开始换芯,发布全新AI版终端
java·人工智能·intellij-idea