充电桩硬件发送报文有时多条一起发送,所以在服务器端要拆分包,直接上代码
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;
/**
* 解码器<br>
* 解决粘包问题
*
* @author icojoo
*
*/
@Slf4j
public class MyDecoder extends MessageToMessageDecoder<byte[]> {
@Override
protected void decode(ChannelHandlerContext ctx, byte[] msg, List<Object> 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<Object> 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<SocketChannel> {
@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);
}
}