Netty详细教程 - 从入门到精通

目录

1. 什么是Netty

1.1 简单理解

1.2 官方定义

1.3 核心特点

2. 为什么需要Netty

2.1 传统IO模型的问题

阻塞IO(BIO)的痛点

NIO的复杂性

2.2 Netty的解决方案

3. Netty核心概念

3.1 整体架构图

3.2 Channel(通道)

3.3 EventLoop(事件循环)

3.4 ChannelHandler(处理器)

3.5 ChannelPipeline(处理器链)

3.6 Bootstrap(启动器)

4. 环境搭建和第一个程序

4.1 环境准备

4.2 第一个Echo服务器

4.3 第一个Echo客户端

4.4 运行和测试

5. Channel详解

5.1 Channel的生命周期

5.2 Channel的配置选项

5.3 Channel的操作方法

5.4 不同类型的Channel

6. ChannelHandler和ChannelPipeline

6.1 ChannelHandler类型详解

6.2 ChannelPipeline操作

6.3 处理器间的通信

6.4 自定义处理器最佳实践

7. EventLoop和线程模型

7.1 EventLoop工作原理

7.2 Reactor模型实现

7.3 线程模型优化

7.4 EventLoop最佳实践

8. 编解码器详解

8.1 内置编解码器

8.2 自定义编解码器

8.3 序列化编解码器

8.4 编解码器最佳实践

9. 常见应用场景实战

9.1 聊天服务器

9.2 HTTP服务器

9.3 TCP代理服务器

10. 性能优化技巧

10.1 内存管理优化

10.2 线程模型优化

10.3 网络优化

10.4 监控和调优

11. 最佳实践

11.1 架构设计最佳实践

11.2 错误处理最佳实践

11.3 安全最佳实践

12. 问题排查和调试

12.1 常见问题诊断

总结

🎯 核心收获

📋 关键要点回顾

架构设计

编程模式

性能优化

🚀 进阶方向

💡 实践建议

🔧 开发检查清单

 


1. 什么是Netty

1.1 简单理解

想象一下你要开一家在线外卖店

传统方式(原生Java Socket)

  • 你需要亲自接电话、记录订单、安排配送
  • 每个客户都要你亲自处理,效率很低
  • 处理过程中容易出错,需要大量重复工作

使用Netty

  • 就像有了一套完整的外卖管理系统
  • 自动接收订单、智能分配任务、高效处理
  • 你只需要关注菜品制作(核心业务逻辑)

1.2 官方定义

Netty是一个基于NIO的客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如协议服务器和客户端。它极大地简化了网络编程,例如TCP和UDP套接字服务器的开发。

1.3 核心特点

// Netty让复杂的网络编程变得简单
public class SimpleNettyServer {
    public static void main(String[] args) {
        // 只需要几行代码就能创建一个高性能服务器
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new MyChannelInitializer());
        
        bootstrap.bind(8080); // 绑定端口,服务器就启动了!
    }
}

主要优势

  • 🚀 高性能:基于NIO,支持数十万并发连接
  • 🛡️ 稳定可靠:经过大量项目验证,内存管理优秀
  • 🔧 易于使用:API设计简洁,开发效率高
  • 🎯 功能丰富:内置多种协议支持和编解码器

2. 为什么需要Netty

2.1 传统IO模型的问题

阻塞IO(BIO)的痛点
// 传统BIO服务器的问题
public class TraditionalBIOServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);
        
        while (true) {
            // 问题1:accept()会阻塞,同时只能处理一个连接
            Socket clientSocket = serverSocket.accept();
            
            // 问题2:每个连接都需要一个线程
            new Thread(() -> {
                try {
                    handleClient(clientSocket); // 处理客户端请求
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start(); // 问题3:线程创建销毁开销大
        }
    }
    
    private static void handleClient(Socket clientSocket) throws IOException {
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(clientSocket.getInputStream()));
        
        String line;
        while ((line = reader.readLine()) != null) { // 问题4:读取也会阻塞
            System.out.println("收到消息: " + line);
        }
    }
}

BIO的问题总结

  1. 一连接一线程:1万个连接需要1万个线程
  2. 线程开销大:创建、切换、销毁都消耗资源
  3. 阻塞等待:线程大部分时间在等待IO
  4. 内存消耗:每个线程默认占用1MB内存
NIO的复杂性
// 原生NIO代码复杂难懂
public class RawNIOServer {
    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        serverChannel.bind(new InetSocketAddress(8080));
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        
        while (true) {
            selector.select(); // 等待事件
            
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectedKeys.iterator();
            
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                
                if (key.isAcceptable()) {
                    // 处理连接事件
                    handleAccept(serverChannel, selector);
                } else if (key.isReadable()) {
                    // 处理读事件
                    handleRead(key);
                }
            }
        }
    }
    
    // 大量样板代码...
}

原生NIO的问题

  • 代码复杂,容易出错
  • 需要处理很多底层细节
  • 半包、粘包问题需要自己解决
  • 跨平台兼容性问题

2.2 Netty的解决方案

// Netty让一切变得简单
public class NettyServer {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new StringDecoder());
                            ch.pipeline().addLast(new StringEncoder());
                            ch.pipeline().addLast(new MyServerHandler());
                        }
                    });
            
            ChannelFuture future = bootstrap.bind(8080).sync();
            System.out.println("服务器启动成功,端口:8080");
            
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

// 业务处理器
class MyServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        String message = (String) msg;
        System.out.println("收到消息: " + message);
        
        // 回复消息
        ctx.writeAndFlush("服务器收到: " + message);
    }
}

Netty的优势

  • ✅ 代码简洁清晰
  • ✅ 高性能,支持数十万并发
  • ✅ 自动处理半包粘包
  • ✅ 丰富的编解码器
  • ✅ 优秀的内存管理

3. Netty核心概念

3.1 整体架构图

客户端请求 → Bootstrap → Channel → ChannelPipeline → ChannelHandler
                    ↓
            EventLoopGroup → EventLoop → 处理IO事件
                    ↓
            ByteBuf ← 数据传输 ← Future/Promise

3.2 Channel(通道)

生活比喻:Channel就像电话线,负责连接双方进行通信。

// Channel的基本概念
public class ChannelExample {
    public void channelBasics() {
        // Channel代表一个网络连接
        // 可以是客户端连接,也可以是服务端连接
        
        // 不同类型的Channel
        NioSocketChannel clientChannel;        // 客户端TCP连接
        NioServerSocketChannel serverChannel;  // 服务端TCP监听
        NioDatagramChannel udpChannel;         // UDP连接
        
        // Channel的生命周期
        // ChannelRegistered → ChannelActive → ChannelInactive → ChannelUnregistered
    }
}

// Channel使用示例
public class ChannelOperationExample extends ChannelInboundHandlerAdapter {
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        
        // 获取连接信息
        SocketAddress localAddress = channel.localAddress();
        SocketAddress remoteAddress = channel.remoteAddress();
        
        System.out.println("新连接建立:");
        System.out.println("本地地址: " + localAddress);
        System.out.println("远程地址: " + remoteAddress);
        
        // 发送欢迎消息
        channel.writeAndFlush("欢迎连接到服务器!");
    }
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        Channel channel = ctx.channel();
        
        // 检查连接是否还活跃
        if (channel.isActive()) {
            System.out.println("处理消息: " + msg);
            
            // 异步写入数据
            ChannelFuture future = channel.writeAndFlush("服务器回复: " + msg);
            
            // 添加监听器处理写入结果
            future.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) {
                    if (future.isSuccess()) {
                        System.out.println("消息发送成功");
                    } else {
                        System.out.println("消息发送失败: " + future.cause());
                    }
                }
            });
        }
    }
}

3.3 EventLoop(事件循环)

生活比喻:EventLoop就像餐厅服务员,不断地巡视桌子,看哪桌有需要就去处理。

// EventLoop工作原理演示
public class EventLoopExample {
    public static void main(String[] args) {
        // 创建EventLoopGroup
        EventLoopGroup group = new NioEventLoopGroup(4); // 4个EventLoop
        
        try {
            // 每个EventLoop可以处理多个Channel
            for (int i = 0; i < 10; i++) {
                final int channelId = i;
                
                // 提交任务到EventLoop
                group.next().execute(() -> {
                    System.out.println("处理Channel " + channelId + 
                                     " 的任务,线程: " + Thread.currentThread().getName());
                });
            }
            
            Thread.sleep(2000);
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}

// EventLoop的任务调度
public class EventLoopTaskExample {
    private EventLoopGroup group = new NioEventLoopGroup();
    
    public void scheduleTask() {
        EventLoop eventLoop = group.next();
        
        // 延迟执行任务
        eventLoop.schedule(() -> {
            System.out.println("延迟任务执行了");
        }, 5, TimeUnit.SECONDS);
        
        // 周期性执行任务
        eventLoop.scheduleAtFixedRate(() -> {
            System.out.println("周期性任务: " + new Date());
        }, 0, 2, TimeUnit.SECONDS);
    }
}

3.4 ChannelHandler(处理器)

生活比喻:ChannelHandler就像工厂流水线上的工人,每个人负责一道工序。

// 入站处理器(处理接收到的数据)
public class MyInboundHandler extends ChannelInboundHandlerAdapter {
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("入站处理器收到消息: " + msg);
        
        // 处理消息(比如解密、解压等)
        String processedMsg = "处理后的消息: " + msg;
        
        // 传递给下一个处理器
        ctx.fireChannelRead(processedMsg);
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        System.out.println("发生异常: " + cause.getMessage());
        ctx.close(); // 关闭连接
    }
}

// 出站处理器(处理要发送的数据)
public class MyOutboundHandler extends ChannelOutboundHandlerAdapter {
    
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
        System.out.println("出站处理器准备发送: " + msg);
        
        // 处理消息(比如加密、压缩等)
        String processedMsg = "加密后的消息: " + msg;
        
        // 传递给下一个处理器
        ctx.write(processedMsg, promise);
    }
}

// 双向处理器
public class MyDuplexHandler extends ChannelDuplexHandler {
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("双向处理器读取: " + msg);
        ctx.fireChannelRead(msg);
    }
    
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
        System.out.println("双向处理器写入: " + msg);
        ctx.write(msg, promise);
    }
}

3.5 ChannelPipeline(处理器链)

生活比喻:ChannelPipeline就像工厂的流水线,数据按顺序经过每道工序。

public class PipelineExample {
    
    public void setupPipeline(SocketChannel ch) {
        ChannelPipeline pipeline = ch.pipeline();
        
        // 入站方向:从上到下执行
        pipeline.addLast("decoder", new StringDecoder());      // 1. 解码
        pipeline.addLast("logger", new LoggingHandler());      // 2. 日志
        pipeline.addLast("business", new BusinessHandler());   // 3. 业务处理
        
        // 出站方向:从下到上执行
        pipeline.addLast("encoder", new StringEncoder());      // 4. 编码
    }
}

// 数据流向演示
public class DataFlowHandler extends ChannelInboundHandlerAdapter {
    private String name;
    
    public DataFlowHandler(String name) {
        this.name = name;
    }
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println(name + " 处理入站数据: " + msg);
        
        // 继续传递给下一个处理器
        ctx.fireChannelRead(msg);
        
        // 如果要发送数据,会走出站流程
        if ("Handler3".equals(name)) {
            ctx.writeAndFlush("回复消息");
        }
    }
}

// 完整的Pipeline示例
public class CompletePipelineExample {
    public static void main(String[] args) {
        EmbeddedChannel channel = new EmbeddedChannel();
        
        // 构建处理器链
        channel.pipeline()
               .addLast("handler1", new DataFlowHandler("Handler1"))
               .addLast("handler2", new DataFlowHandler("Handler2"))
               .addLast("handler3", new DataFlowHandler("Handler3"));
        
        // 模拟接收数据
        channel.writeInbound("测试消息");
        
        // 读取响应
        Object response = channel.readOutbound();
        System.out.println("最终响应: " + response);
    }
}

3.6 Bootstrap(启动器)

生活比喻:Bootstrap就像开店的准备工作,配置好所有必要的设置。

// 服务端启动器
public class ServerBootstrapExample {
    public void startServer() {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);    // 处理连接
        EventLoopGroup workerGroup = new NioEventLoopGroup(8);  // 处理数据
        
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap
                .group(bossGroup, workerGroup)           // 设置线程组
                .channel(NioServerSocketChannel.class)   // 设置通道类型
                .option(ChannelOption.SO_BACKLOG, 128)   // 设置连接队列大小
                .childOption(ChannelOption.SO_KEEPALIVE, true) // 保持连接活跃
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        // 配置处理器链
                        ch.pipeline().addLast(new MyServerHandler());
                    }
                });
            
            // 绑定端口并启动服务器
            ChannelFuture future = bootstrap.bind(8080).sync();
            System.out.println("服务器启动成功,监听端口: 8080");
            
            // 等待服务器关闭
            future.channel().closeFuture().sync();
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

// 客户端启动器
public class ClientBootstrapExample {
    public void connectToServer() {
        EventLoopGroup group = new NioEventLoopGroup();
        
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap
                .group(group)                            // 设置线程组
                .channel(NioSocketChannel.class)         // 设置通道类型
                .option(ChannelOption.SO_KEEPALIVE, true) // 保持连接
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new MyClientHandler());
                    }
                });
            
            // 连接服务器
            ChannelFuture future = bootstrap.connect("localhost", 8080).sync();
            System.out.println("连接服务器成功");
            
            // 发送消息
            Channel channel = future.channel();
            channel.writeAndFlush("Hello Server!");
            
            // 等待连接关闭
            future.channel().closeFuture().sync();
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}

4. 环境搭建和第一个程序

4.1 环境准备

Maven依赖

<dependencies>
    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.1.94.Final</version>
    </dependency>
    
    <!-- 日志依赖(可选) -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.4.8</version>
    </dependency>
</dependencies>

Gradle依赖

dependencies {
    implementation 'io.netty:netty-all:4.1.94.Final'
    implementation 'ch.qos.logback:logback-classic:1.4.8'
}

4.2 第一个Echo服务器

// 服务端主类
public class EchoServer {
    private final int port;
    
    public EchoServer(int port) {
        this.port = port;
    }
    
    public void start() throws InterruptedException {
        // 创建两个EventLoopGroup
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);    // 接受连接
        EventLoopGroup workerGroup = new NioEventLoopGroup();   // 处理连接
        
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(port))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            // 添加处理器到pipeline
                            ch.pipeline().addLast(new EchoServerHandler());
                        }
                    });
            
            // 绑定端口,开始接受连接
            ChannelFuture future = bootstrap.bind().sync();
            System.out.println("Echo服务器启动成功,监听端口: " + port);
            
            // 等待服务器socket关闭
            future.channel().closeFuture().sync();
            
        } finally {
            // 优雅关闭
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        new EchoServer(8080).start();
    }
}

// 服务端处理器
@ChannelHandler.Sharable  // 标记这个处理器可以被多个Channel共享
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf in = (ByteBuf) msg;
        
        // 读取接收到的数据
        String message = in.toString(CharsetUtil.UTF_8);
        System.out.println("服务器收到: " + message);
        
        // 原样返回给客户端(Echo)
        ctx.write(in);
    }
    
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        // 将挂起的消息冲刷到远程节点,并关闭该Channel
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
           .addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 打印异常堆栈跟踪
        cause.printStackTrace();
        // 关闭该Channel
        ctx.close();
    }
}

4.3 第一个Echo客户端

// 客户端主类
public class EchoClient {
    private final String host;
    private final int port;
    
    public EchoClient(String host, int port) {
        this.host = host;
        this.port = port;
    }
    
    public void start() throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .remoteAddress(new InetSocketAddress(host, port))
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new EchoClientHandler());
                        }
                    });
            
            // 连接到远程节点,阻塞等待直到连接完成
            ChannelFuture future = bootstrap.connect().sync();
            System.out.println("客户端连接成功");
            
            // 阻塞,直到Channel关闭
            future.channel().closeFuture().sync();
            
        } finally {
            // 关闭线程组并释放所有资源
            group.shutdownGracefully().sync();
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        new EchoClient("localhost", 8080).start();
    }
}

// 客户端处理器
@ChannelHandler.Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        // 当连接建立时,发送一条消息
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello Netty!", CharsetUtil.UTF_8));
    }
    
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
        // 接收服务器的回显消息
        String received = msg.toString(CharsetUtil.UTF_8);
        System.out.println("客户端收到: " + received);
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

4.4 运行和测试

// 测试步骤
public class EchoTest {
    public static void main(String[] args) {
        // 1. 启动服务器
        new Thread(() -> {
            try {
                new EchoServer(8080).start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        
        // 2. 等待服务器启动
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        // 3. 启动多个客户端测试
        for (int i = 0; i < 3; i++) {
            final int clientId = i;
            new Thread(() -> {
                try {
                    System.out.println("启动客户端 " + clientId);
                    new EchoClient("localhost", 8080).start();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

5. Channel详解

5.1 Channel的生命周期

public class ChannelLifecycleHandler extends ChannelInboundHandlerAdapter {
    
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        System.out.println("1. Handler被添加到Pipeline");
    }
    
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) {
        System.out.println("2. Channel已注册到EventLoop");
    }
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("3. Channel已激活,连接建立成功");
        
        // 连接建立后的初始化工作
        Channel channel = ctx.channel();
        System.out.println("连接信息:");
        System.out.println("- 本地地址: " + channel.localAddress());
        System.out.println("- 远程地址: " + channel.remoteAddress());
        System.out.println("- 是否打开: " + channel.isOpen());
        System.out.println("- 是否激活: " + channel.isActive());
    }
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("4. 接收到数据: " + msg);
        ctx.fireChannelRead(msg);
    }
    
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        System.out.println("5. 数据读取完成");
        ctx.fireChannelReadComplete();
    }
    
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        System.out.println("6. Channel已失活,连接断开");
    }
    
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) {
        System.out.println("7. Channel已从EventLoop注销");
    }
    
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        System.out.println("8. Handler从Pipeline移除");
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        System.out.println("异常发生: " + cause.getMessage());
        ctx.close(); // 关闭连接
    }
}

5.2 Channel的配置选项

public class ChannelOptionsExample {
    
    public void configureServerChannel() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                
                // 服务端Channel选项
                .option(ChannelOption.SO_BACKLOG, 128)        // 连接队列大小
                .option(ChannelOption.SO_REUSEADDR, true)     // 地址重用
                
                // 客户端Channel选项(childOption)
                .childOption(ChannelOption.SO_KEEPALIVE, true)    // 保持连接活跃
                .childOption(ChannelOption.TCP_NODELAY, true)     // 禁用Nagle算法
                .childOption(ChannelOption.SO_RCVBUF, 32 * 1024)  // 接收缓冲区大小
                .childOption(ChannelOption.SO_SNDBUF, 32 * 1024)  // 发送缓冲区大小
                .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000); // 连接超时
    }
    
    public void configureClientChannel() {
        Bootstrap bootstrap = new Bootstrap();
        
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                
                // 客户端选项
                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                .option(ChannelOption.SO_RCVBUF, 64 * 1024)
                .option(ChannelOption.SO_SNDBUF, 64 * 1024);
    }
}

5.3 Channel的操作方法

public class ChannelOperationsExample extends ChannelInboundHandlerAdapter {
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        
        // 1. 基本信息查询
        System.out.println("Channel信息:");
        System.out.println("ID: " + channel.id());
        System.out.println("本地地址: " + channel.localAddress());
        System.out.println("远程地址: " + channel.remoteAddress());
        System.out.println("是否打开: " + channel.isOpen());
        System.out.println("是否活跃: " + channel.isActive());
        System.out.println("是否可写: " + channel.isWritable());
        
        // 2. 写入操作
        demonstrateWriteOperations(channel);
        
        // 3. 异步操作
        demonstrateAsyncOperations(channel);
        
        // 4. 属性操作
        demonstrateAttributeOperations(channel);
    }
    
    private void demonstrateWriteOperations(Channel channel) {
        // 写入但不刷新
        channel.write("消息1");
        channel.write("消息2");
        channel.flush(); // 统一刷新
        
        // 写入并刷新
        channel.writeAndFlush("消息3");
        
        // 使用ByteBuf
        ByteBuf buffer = Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8);
        channel.writeAndFlush(buffer);
    }
    
    private void demonstrateAsyncOperations(Channel channel) {
        // 异步写入
        ChannelFuture future = channel.writeAndFlush("异步消息");
        
        // 添加监听器
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) {
                if (future.isSuccess()) {
                    System.out.println("消息发送成功");
                } else {
                    System.out.println("消息发送失败: " + future.cause());
                }
            }
        });
        
        // 或者使用Lambda表达式
        future.addListener((ChannelFutureListener) f -> {
            if (f.isSuccess()) {
                System.out.println("发送成功");
            } else {
                System.out.println("发送失败: " + f.cause());
            }
        });
    }
    
    private void demonstrateAttributeOperations(Channel channel) {
        // 定义属性键
        AttributeKey<String> USER_ID = AttributeKey.valueOf("userId");
        AttributeKey<Date> LOGIN_TIME = AttributeKey.valueOf("loginTime");
        
        // 设置属性
        channel.attr(USER_ID).set("user123");
        channel.attr(LOGIN_TIME).set(new Date());
        
        // 获取属性
        String userId = channel.attr(USER_ID).get();
        Date loginTime = channel.attr(LOGIN_TIME).get();
        
        System.out.println("用户ID: " + userId);
        System.out.println("登录时间: " + loginTime);
    }
}

5.4 不同类型的Channel

// TCP服务端Channel
public class TcpServerChannelExample {
    public void createTcpServer() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.channel(NioServerSocketChannel.class); // TCP服务端
        
        // 配置TCP特有选项
        bootstrap.option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true);
    }
}

// TCP客户端Channel
public class TcpClientChannelExample {
    public void createTcpClient() {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.channel(NioSocketChannel.class); // TCP客户端
        
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.TCP_NODELAY, true);
    }
}

// UDP Channel
public class UdpChannelExample {
    public void createUdpServer() {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioDatagramChannel.class) // UDP
                .handler(new UdpServerHandler());
        
        // UDP特有选项
        bootstrap.option(ChannelOption.SO_BROADCAST, true)
                .option(ChannelOption.SO_RCVBUF, 64 * 1024);
    }
}

// UDP处理器
public class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
    
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) {
        // 读取UDP数据包
        ByteBuf content = msg.content();
        String message = content.toString(CharsetUtil.UTF_8);
        InetSocketAddress sender = msg.sender();
        
        System.out.println("收到UDP消息: " + message + " 来自: " + sender);
        
        // 回复UDP消息
        String response = "服务器收到: " + message;
        ByteBuf responseBuf = Unpooled.copiedBuffer(response, CharsetUtil.UTF_8);
        DatagramPacket responsePacket = new DatagramPacket(responseBuf, sender);
        
        ctx.writeAndFlush(responsePacket);
    }
}

6. ChannelHandler和ChannelPipeline

6.1 ChannelHandler类型详解

// 入站处理器 - 处理读取数据
public class CustomInboundHandler extends ChannelInboundHandlerAdapter {
    private String name;
    
    public CustomInboundHandler(String name) {
        this.name = name;
    }
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("[" + name + "] 入站处理: " + msg);
        
        // 修改消息内容
        String message = msg.toString();
        String processedMessage = "[" + name + "处理] " + message;
        
        // 传递给下一个处理器
        ctx.fireChannelRead(processedMessage);
    }
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("[" + name + "] 连接激活");
        ctx.fireChannelActive();
    }
}

// 出站
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值