netty 自定义16进制协议 汽车充电app项目实战

arctan0 2016-03-09

有关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

相关推荐