java Netty处理充电桩报文粘包、拆包方案解决

充电桩硬件发送报文有时多条一起发送,所以在服务器端要拆分包,直接上代码

package com.icojoo.chargeNetty.tcpIp;
import com.icojoo.chargeNetty.utils.BytesUtil;
import com.icojoo.chargeNetty.utils.IcojooUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import lombok.extern.slf4j.Slf4j;
import java.net.InetSocketAddress;
import java.util.List;

/**
 * 解码器
* 解决粘包问题 * * @author icojoo * */ @Slf4j public class MyDecoder extends MessageToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, byte[] msg, List out) throws Exception { try { if (IcojooUtil.isYunKuaiChong(msg)) { // 云快充 unpackSH(msg, out); }else { log.info( " unkown proctrol 未知协议类型" ); //out.add(msg); } } catch (Exception e) { log.error(" decode Exception : " + e.toString()); } } /** * 云快充拆包 */ private void unpackSH(byte[] msg, List out) { // 获取报文的长度帧,并转化10进制字节,在加上起始帧1个字节+长度帧1个字节+效验帧2个字节,所以+4, int len = BytesUtil.toInt2(msg, 1)+4; if (msg.length <= len) { // 一个整包 out.add(msg); } else { // 1.取出一个包的数据 byte[] array = new byte[len]; System.arraycopy(msg, 0, array, 0, len); out.add(array); // 2. 多余的数据继续分包 int other = msg.length - len; array = new byte[other]; System.arraycopy(msg, len, array, 0, array.length); unpackSH(array, out); } } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { super.channelActive(ctx); InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress(); String ip = address.toString(); log.info("channelActive --> RamoteAddress : " + ip + " connected "); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { log.error(" exceptionCaught : " + cause.toString() + " ctx = " + ctx.channel().toString() ); ctx.close(); } }
package com.icojoo.chargeNetty.tcpIp;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class ServerChannelInitializer extends ChannelInitializer {

    @Autowired
    ServerChannelHandler serverChannelHandler;

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        // 字符串编解码器
        pipeline.addLast("decoder",new ByteArrayDecoder());
        pipeline.addLast("encoder",new ByteArrayEncoder());
        //IdleStateHandler心跳机制,如果超时触发Handle中userEventTrigger()方法
        pipeline.addLast("idleStateHandler", new IdleStateHandler(15,0,0, TimeUnit.MINUTES));
        //拆包这个是重点
        pipeline.addLast(new MyDecoder());
        // 自定义Handler
        pipeline.addLast("serverChannelHandler",serverChannelHandler);
    }
}

你可能感兴趣的:(充电桩系统开发,java)