概要
接触过物联网的小伙伴都知道, 很多私有协议在正式通信前都需要进行握手这一操作, 如果握手失败将无法进行后续的业务通信
例如在通信前可能需要确认设备型号, 协议版本, 元信息版本, 设备状态,地域信息等等, 这些都是必须在业务通信前要确定.
此文将展示如何通过Nettyx中的ChannelInterceptor来实现一个握手器, 注意千万别和Spring中的ChannelInterceptor搞混了!!
先引入依赖
确保使用最新版本nettyx,此处为了演示使用了如下版本
<dependency>
<groupId>io.github.fbbzl</groupId>
<artifactId>nettyx</artifactId>
<version>2.2.22-RELEASE</version>
</dependency>
ChannelInterceptor
Nettyx提供了ChannelInterceptor这一工具
以下将展示如何实现一个简单的确认通信协议版本号的握手器
ChannelInterceptor默认会拦截所有IO事件直到调用free相关方法, 相反的, 如果调用reset方法将会重新开始拦截IO事件
@Slf4j
public class ProtocolVersionHandShaker extends ChannelInterceptor<MyMessage> {
// 使用的协议版本
private String usingVersion;
@Override
public void preChannelActive(ChannelHandlerContext ctx) {
// 如果是握手发起方, 需要在active中调用发起握手的请求消息
// sendCheckProtocolVersionRequest(ctx);
log.info("has send handshake req");
}
// msg 为用户自行封装的消息实体, 本示例中仅作参考
@Override
protected void preChannelRead(ChannelHandlerContext ctx, MyMessage msg) throws Exception {
try {
String version = msg.getVersion();
if(version!=null && version.length()>0) {
this.usingVersion = msg.getVersion();
// 核心步骤, freeAndActive方法会将当前拦截器free掉, 后续此拦截器将不会参与消息解析
// 如果在free掉此拦截器之后, 后续又需要恢复此拦截器, 只需调用reset()方法即可
super.freeAndActive(ctx);
}
} catch(Exception unknown) {
// 如果是握手发起方的话, 出现异常可能会要进行重试, 重新发送版本核对请求
//sendCheckProtocolVersionRequest(ctx);
log.warn("protocol version check failed, response is [{}]", msg);
}
}
@Override
protected void preUserEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (ChannelEvents.isReadIdle(evt)) {
log.info("intercepted channel read idle");
}
}
@Override
protected void preChannelReadComplete(ChannelHandlerContext ctx) {
log.debug("intercepted channel read complete");
}
==========================================================================
如果后续需要重新恢复所有拦截器, 可以调用ChannelInterceptors.resetAll()恢复ChannelPipeline中所有拦截器.
如果只需要恢复单个拦截器直接从ChannelPipeline中根据名字获取handler, 强转成ChannelInterceptor之后调用reset即可