netty 自定义16进制协议 汽车充电app项目实战
有关netty基本知识就不在此做过多说明、大家可以baidu学习基本知识。本文给大家提供一个netty项目实例供大家学习、也可在项目中使用。
项目说明:
用户使用手机app下发消息给充电设备、从而达到自动给电动汽车充电、也就是现在流行的充电桩。
定义协议如下:
发起报文格式
域名字节数说明
起始域1起始字节,固定为0x68
版本1该版本文件固定为0x01
功能码1消息类型,下文做解析
充电设施ID4设备唯一编码
包号1针对需要多包传输的数据
包号起始位0x01
数据长度2单包数据域字节数,单包长度不超过500字节
数据n数据域,不同的功能码对应不同的数据定义
校验码1采用累积和校验,计算范围为数据域
反馈报文格式
域名字节数说明
起始域1起始字节,固定为0x68
版本1该版本文件固定为0x01
功能码1消息类型,下文将详细解析
充电设施ID4设备唯一编码
反馈标志码1反馈标志码下文做解析
包号1针对需要多包传输的数据
数据长度2单包数据域字节数,单包长度不超过500字节
数据n数据域,不同的功能码对应不同的数据定义
校验码1采用累积和校验,计算范围为数据域
具体解码编码代码如下:
解码:
//68开头
if(hex.startsWith("68")){
ParamInforesult=newParamInfo();
//设置版本号
result.setVersion(DigitalUtils.hex2Algorism(hex.substring(2,4)));
//设置功能码
result.setServiceName(hex.substring(4,6));
//设置充电桩编号(16进制转10进制,前面补0)
result.setStubId(StringUtils.leftPad(String.valueOf(DigitalUtils.hex2Algorism(hex.substring(6,14))),8,"0"));
//数据索引块(包号)
result.setDataIdx(DigitalUtils.hex2Algorism(hex.substring(14,16)));
//数据长度
result.setDataLength(DigitalUtils.hex2Algorism(hex.substring(16,20)));
//数据长度检查
if(hex.length()!=20+result.getDataLength()*2+2){
result.setErrCode("F1");
returnresult;
}
//数据拆分
StringdataHex=hex.substring(20,20+result.getDataLength()*2);
if(result.getDataLength()>0){
intstartIdx=0;
List<StructInfo>structureList=ConfigUtils.getDecodeStruct().get(result.getServiceName());
if(structureList!=null){
for(StructInfostructInfo:structureList){
result.addRequestData(structInfo.getName(),structInfo.cover(dataHex,startIdx));
startIdx=startIdx+structInfo.getLength()*2;
}
}else{
result.setErrCode("05");
returnresult;
}
}
//校验运算
StringverifyString=hex.substring(20+result.getDataLength()*2,20+result.getDataLength()*2+2);
if(!verifyString.equals(DigitalUtils.ADD(dataHex))){
result.setErrCode("07");
returnresult;
}
returnresult;
}
编码:
//起始域+版本+功能码+充电桩编号+错误位
hexSb.append("68").append("01").append(param.getServiceName()).append(param.getStubId()).append(param.getErrCode()).append("01");
List<StructInfo>structList=ConfigUtils.getEncodeStruct().get(param.getServiceName());
//生成数据
StringBufferdataHex=newStringBuffer();
//有返回数据结构且是正常返回
if(structList!=null&&"00".equals(param.getErrCode())){
for(StructInfostructInfo:structList){
Objectvalue=param.getResponseDate().get(structInfo.getName());
//TODO不在此范围内的转型报错
if(structInfo.getType()==1){
//如果返回数据类型必须为ascii
if(valueinstanceofString){
dataHex.append(DigitalUtils.StringToAscii((String)value));
}
}elseif(structInfo.getType()==0){
//如果返回数据类型必须为hex
if(valueinstanceofInteger){
dataHex.append(DigitalUtils.algorism2Hex((Integer)value,structInfo.getLength()*2));
}elseif(valueinstanceofBigDecimal){
dataHex.append(DigitalUtils.algorism2Hex(((BigDecimal)value).intValue(),structInfo.getLength()*2));
}elseif(valueinstanceofString){
dataHex.append(value);
}
}
}
项目架构:
spring注解、jdbc连接池、membercache、netty4。因项目比较大、如需要项目源码可联系我qq451366323