package cn.com.abc.obddatacollect.net; import io.netty.channel.*; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import io.netty.handler.timeout.IdleStateHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; /** * * @author 28338007@qq.com * 基于 LengthFieldBasedFrameDecoder 解码链初始化 * @time 2019年12月5日 */ @Component public class LengthFieldServerHandlerInitializer extends ChannelInitializer<SocketChannel> { private static final Logger logger = LoggerFactory.getLogger(NetServer.class); @Value("${netty.sign-or-encrypt:4}") private int signOrEncrypt; //1:验签并加密,2:只验签不加密,3:只加密不验签 @Value("${netty.agreement-type:gb}") private String agreementType; //协议类型:gb(国标),ht(私有) @Value("${netty.idle-count:20}") //链路空闲次数(每次15秒) private int idleCount; @Value("${netty.send-rate:3}") private int sendRate ; //设置发送频率,0:不限制,其他值为跳过所设值后才发送消息 @Value("${netty.check-login:1}") private int checkLogin ; //设置发送频率,0:不限制,其他值为跳过所设值后才发送消息 private static final int MAX_FRAME_LENGTH=1024*512; //最大包长度 private static final int LENGTH_FIELD_OFFSET=22; //长度字段在包中的位置 private static final int LENGTH_FIELD_LENGTH=2; //长度字段数占的字节数 //添加到长度字段的补偿值,本系统报文,最后有一个字节的校验码,所以这里的补偿值是1; // LENGTH_ADJUSTMENT = 整个数据包长度- LENGTH_FIELD_OFFSET - LENGTH_FIELD_LENGTH - 数据段的长度值 //本协议中最后一个字节的校验码没有包含在 LENGTH_FIELD_OFFSET+LENGTH_FIELD_LENGTH + 数据段的长度值 中,所以这个地方的值为1 private static final int LENGTH_ADJUSTMENT=1; private static final int INITIAL_BYTES_TO_STRIP=2; //从解码帧中头部去除的字节数 @Override protected void initChannel(SocketChannel ch) { ChannelInboundHandlerAdapter businessHandler; switch (signOrEncrypt){ case Constants.SIGN_AND_ENCRYPT: businessHandler = new LengthFieldDecodeWithSignatureAndEncryptHandler(idleCount,agreementType,sendRate,checkLogin); break; case Constants.ENCRYPT_ONLY: businessHandler = new LengthFieldDecodeWithEncryptHandler(idleCount,agreementType,sendRate,checkLogin); break; case Constants.NO_SIGN_NO_ENCRYPT: businessHandler = new LengthFieldDecodeHandler(idleCount,agreementType,sendRate,checkLogin); break; default: businessHandler = new LengthFieldDecodeWithSignatureHandler(idleCount,agreementType,sendRate,checkLogin); break; } ch.pipeline() .addLast( new ExceptionHandler(), //每隔15秒的时间内如果没有接受到任何的read事件的话,则会触发userEventTriggered事件,并指定IdleState的类型为READER_IDLE new IdleStateHandler(15, 0, 0, TimeUnit.SECONDS), //根据报结构中指定数据长度的报解析 new LengthFieldBasedFrameDecoder(MAX_FRAME_LENGTH,LENGTH_FIELD_OFFSET,LENGTH_FIELD_LENGTH,LENGTH_ADJUSTMENT,INITIAL_BYTES_TO_STRIP), //new LengthFieldPrepender(2), //new LengthFieldDecodeWithEncryptHandler(idleCount) businessHandler ); } static final class ExceptionHandler extends ChannelDuplexHandler { @Override public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { super.close(ctx, promise); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { final String remoteAddress = ctx.channel().remoteAddress().toString(); ctx.flush(); ctx.close(); logger.error("客户端强制断开了一个连接 {}", remoteAddress); } } }
LengthFieldBasedFrameDecoder 真实案例使用
于 2022-11-23 16:21:22 首次发布