创建和001课程一致pipeline主要是处理器
handlerAdded
↓
channelRegistered //代码没写
↓
channelActive
↓
channelRead 可能执行多次
↓
channelReadComplete 可能执行多次
↓
channelInactive
↓
channelUnregistered //代码没写
↓
handlerRemoved
代码
class LifecycleHandler extends SimpleChannelInboundHandler<String> {
// 每个连接独有一个实例,所以这两个计数器是"这条连接"自己的计数
private int readCount = 0;
@Override
public void handlerAdded(ChannelHandlerContext ctx) {
// 触发时机:Handler 被加入 pipeline 时(通常是连接建立的极早期)
System.out.println("① handlerAdded -> 连接到来,装配 Handler,remote=" + ctx.channel().remoteAddress());
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
// 触发时机:TCP 连接真正建立完成(每条连接只触发 1 次)
System.out.println("② channelActive -> 连接已建立(只此一次)");
// 连接建立后,可以主动给客户端发一句欢迎语
ctx.writeAndFlush("欢迎连接 Echo 服务器!随便说点什么,我给你回声~\r\n");
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
// 触发时机:每收到一条数据就调用一次(可触发 N 次)
readCount++;
System.out.println("③ channelRead -> 第 " + readCount + " 次收到消息: " + msg);
ctx.writeAndFlush("ECHO: " + msg + " (这是服务器回显)\r\n");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
// 触发时机:Netty 一次批量读取动作结束后触发(通常紧跟在若干 channelRead 之后)
// 作用:把累积缓冲区里没刷出去的数据一次性刷到网络
System.out.println("④ channelReadComplete -> 本轮读取完成,刷新缓冲区");
ctx.flush();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
// 触发时机:连接断开(客户端关闭 / 网络中断),每条连接只触发 1 次
System.out.println("⑤ channelInactive -> 连接已断开(只此一次),共收到 " + readCount + " 条消息");
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) {
// 触发时机:Handler 从 pipeline 中移除(连接销毁的收尾阶段)
System.out.println("⑥ handlerRemoved -> Handler 被移除,释放资源");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 触发时机:链路中任何 Handler 抛出未捕获异常
System.err.println("⚠ exceptionCaught -> 发生异常: " + cause.getMessage());
// 一般做法:打印异常后关闭连接,避免脏连接
ctx.close();
}
}
客户端连接发送信息测试
① handlerAdded -> 连接到来,装配 Handler,remote=/127.0.0.1:61014
② channelActive -> 连接已建立(只此一次)
③ channelRead -> 第 1 次收到消息: 321
④ channelReadComplete -> 本轮读取完成,刷新缓冲区
④ channelReadComplete -> 本轮读取完成,刷新缓冲区
⑤ channelInactive -> 连接已断开(只此一次),共收到 1 条消息
⑥ handlerRemoved -> Handler 被移除,释放资源
SimpleChannelInboundHandler
它提供两个便利:
- 自动筛选
T消息。 channelRead0()执行完成后自动释放接收到的消息。
channelRead0
客户端发送一次不保证服务端只触发一次channelRead0()。需要使用半包和粘包处理这个问题。