惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
IT之家
IT之家
Hugging Face - Blog
Hugging Face - Blog
Engineering at Meta
Engineering at Meta
爱范儿
爱范儿
博客园 - Franky
博客园 - 【当耐特】
MyScale Blog
MyScale Blog
雷峰网
雷峰网
月光博客
月光博客
云风的 BLOG
云风的 BLOG
博客园 - 司徒正美
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Proofpoint News Feed
The GitHub Blog
The GitHub Blog
N
Netflix TechBlog - Medium
WordPress大学
WordPress大学
罗磊的独立博客
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Y
Y Combinator Blog
Know Your Adversary
Know Your Adversary
宝玉的分享
宝玉的分享
L
Lohrmann on Cybersecurity
S
SegmentFault 最新的问题
L
LangChain Blog
K
Kaspersky official blog
P
Palo Alto Networks Blog
P
Privacy & Cybersecurity Law Blog
美团技术团队
Scott Helme
Scott Helme
B
Blog RSS Feed
T
Threat Research - Cisco Blogs
博客园_首页
L
LINUX DO - 热门话题
腾讯CDC
C
CERT Recently Published Vulnerability Notes
A
About on SuperTechFans
博客园 - 三生石上(FineUI控件)
J
Java Code Geeks
V
V2EX
Martin Fowler
Martin Fowler
T
The Exploit Database - CXSecurity.com
人人都是产品经理
人人都是产品经理
MongoDB | Blog
MongoDB | Blog
Latest news
Latest news
S
Schneier on Security
AWS News Blog
AWS News Blog

个人博客

leetcode经典动态规划解题报告 Netty启动原理 web安全基础知识一 SpringBoot自动配置原理 跟踪SpringMVC请求过程 负载均衡的实现方式与算法 Netty之ByteBuf Netty线程模型 段页式内存管理 fork()与写时复制 fork()与写时复制 Linux内核设计与实现读书笔记一 Dubbo小知识点总结 MyBatis的使用回顾 Dubbo集群容错 Dubbo服务调用过程 InnoDB的锁 SpringBoot启动原理 Maven和Git命令的一些总结 高可用Redis:Redis Cluster
Netty之ChannelHandler
zofun · 2020-05-17 · via 个人博客

文章导航

Channel的生命周期

Channel包含4个状态:

ChannelUnregistered Channel已经被创建,但还未注册到EventLoop
ChannelRegistered Channel已经被注册到EventLoop
ChannelActive Channel处于活动状态,它现在可以接受和发送数据了
ChannelInactive Channel没有连接到远程节点

ChannelHandler的生命周期

ChannelHandler接口定义了一系列生命周期操作:

类型 描述
handlerAdded 当把ChannelHandler添加到ChannelPipeline中时要调用
handlerRemoved 当从ChannelPipeline中移除ChannelHandler时被调用
exceptionCaught 当处理过程中在ChannelPipeline中有错误产生时调用

ChannelInboundHandler接口

YRSkl9.png

ChannelOutboundHandler接口

YRSew6.png

ChannelHandler适配器

YRSJmt.png

资源管理

每当调用ChannelInboundHandler.channelRead()或者ChannelOutboundHandler.write()方法来处理数据时,都需要确保没有任何的资源泄漏。Netty使用引用计数来处理池化的ByteBuf.所以在完全使用某个ByteBuf之后,调整其引用计数是很重要的。
Netty提供了class ResourceLeakDetector,它可以对应用程序缓冲区分配做大约1%的采样率进行内存泄漏检测。相关的开销是非常的小的。

级别 描述
DISABLED 禁止内存泄漏检测
SIMPLE 使用1%的默认采样率检测并报告任何发现的泄漏。(默认)
ADVANCED 使用默认的采样率,报告所发现的任何的泄漏以及对应的消息被访问的位置。
PARANOID 类是于ADVANCED,但是其间会对每次访问都进行采样。这会对性能有较大的影响。

泄漏检测级别可以通过JVM启动选项来设置:
java -Dio.netty.leakDetectionLevel=ADVANCED

ChannelPipeline接口

ChannelPipeline是一个拦截流经Channel的入站和出站事件的ChannelHandler实例链。每一个新创建的Channel都会被分配给一个新的ChannelPipeline,这项关联式永久性的,Channel既不能附加另外一个ChannelPipeline,也不能分离其当前的。
根据事件的起源事件将会被分为ChannelInboundHandler或者ChannelOutboundHandler处理。
YRNLan.png

修改ChannelPipeline

ChannelPipeline可以通过添加、删除或者替换其它的ChannelHandler来实时地修改ChannelPipeline的布局。
YRUIF1.png
ChannelPipeline还提供了访问ChannelHandler的操作:
YRdAgK.png

触发事件

ChannelPipeline的API公开了用于调用入站和出站操作的附加方法。
YRd18P.png
YRdB80.png

ChannelHandlerContext接口

ChannelHandlerContext代表了ChannelHandlerChannelPipeline之间的关联。每当有ChannelHandler添加到ChannelPipeline中时,都会创建ChannelHandlerContextChannelHandlerContext的主要功能就是管理它所关联的ChannelHandler和在同一ChannelPipeline中的其它ChannelHandler之间的交互。

异常处理

Netty提供了几种方式来处理入站和出站过程中出现的异常。

入站异常

如果需要处理入站异常,需要在对应的ChannelInboundHandler中重写exceptionCaught方法。

1
2
3
4
5
6
7
8
public class InboundExceptionHandler extends ChannelInboundHandlerAdapter{
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

一般将异常处理的ChannelHandler放到ChannelPipeline的最后一个位置。这样在整个处理路链中无论哪个环节出了异常都可以得到处理。因为exceptionCaught()的默认实现是将异常转发给下一个HandlerHandler.

处理出站异常

处理出站异常基于以下的机制:

  • 每个出站操作都会返回一个ChannelFuture,注册到ChannelFutureChannelFutureListener将在操作完成时痛殴之该操作时注册成功还是出错了
  • 几乎所有的ChannelOutboundHandler上的方法都会传入一个ChannelPromise的实例,作为ChannelFuture的子类,ChannelPromise也可以被分配用于异步通知的监听器。但是,ChannelPromise还具有提供立即通知的可写方法。

处理方法:

1
2
3
4
5
6
7
8
9
10
ChannelFuture future = channel.write(someMessage);
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture f) {
if (!f.isSuccess()) {
f.cause().printStackTrace();
f.channel().close();
}
}
});

另一种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class OutboundExceptionHandler extends 	   ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg,
ChannelPromise promise) {
promise.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture f) {
if (!f.isSuccess()) {
f.cause().printStackTrace();
f.channel().close();
}
}
});
}
}