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

有关netty基本知识就不在此做过多说明、大家可以baidu学习基本知识。本文给大家提供一个netty 项目实例供大家学习、也可在项目中使用。


项目说明:

用户使用手机app 下发消息给充电设备、从而达到自动给电动汽车充电、也就是现在流行的充电桩。


定义协议如下:

                                            发起报文格式
域  名 字节数 说  明
起始域 1 起始字节,固定为0x68
版本 1 该版本文件固定为0x01
功能码 1 消息类型,下文做解析
充电设施ID 4 设备唯一编码
包号 1 针对需要多包传输的数据
包号起始位0x01
数据长度 2 单包数据域字节数,单包长度不超过500字节
数据 n 数据域,不同的功能码对应不同的数据定义
校验码 1 采用累积和校验,计算范围为数据域

                    反馈报文格式
域  名 字节数 说  明
起始域 1 起始字节,固定为0x68
版本 1 该版本文件固定为0x01
功能码 1 消息类型,下文将详细解析
充电设施ID 4 设备唯一编码
反馈标志码 1 反馈标志码下文做解析
包号 1 针对需要多包传输的数据
数据长度 2 单包数据域字节数,单包长度不超过500字节
数据 n 数据域,不同的功能码对应不同的数据定义
校验码 1 采用累积和校验,计算范围为数据域
具体解码编码代码如下:

解码:

// 68开头
if (hex.startsWith("68")) {


ParamInfo result = new ParamInfo();


// 设置版本号
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");
return result;
}


// 数据拆分
String dataHex = hex.substring(20, 20 + result.getDataLength() * 2);


if (result.getDataLength() > 0) {
int startIdx = 0;


List<StructInfo> structureList = ConfigUtils.getDecodeStruct().get(result.getServiceName());


if (structureList != null) {


for (StructInfo structInfo : structureList) {


result.addRequestData(structInfo.getName(), structInfo.cover(dataHex, startIdx));
startIdx = startIdx + structInfo.getLength() * 2;
}


} else {
result.setErrCode("05");
return result;
}
}


// 校验运算
String verifyString = hex.substring(20 + result.getDataLength() * 2, 20 + result.getDataLength() * 2 + 2);
if (!verifyString.equals(DigitalUtils.ADD(dataHex))) {
result.setErrCode("07");
return result;
}


return result;
}

编码:

// 起始域+版本+功能码+充电桩编号+错误位
hexSb.append("68").append("01").append(param.getServiceName()).append(param.getStubId()).append(param.getErrCode()).append("01");


List<StructInfo> structList = ConfigUtils.getEncodeStruct().get(param.getServiceName());


// 生成数据
StringBuffer dataHex = new StringBuffer();


// 有返回数据结构且是正常返回
if (structList != null && "00".equals(param.getErrCode())) {


for (StructInfo structInfo : structList) {


Object value = param.getResponseDate().get(structInfo.getName());


// TODO 不在此范围内的转型报错
if (structInfo.getType() == 1) {


// 如果返回数据类型必须为ascii
if (value instanceof String) {
dataHex.append(DigitalUtils.StringToAscii((String) value));
}
} else if (structInfo.getType() == 0) {


// 如果返回数据类型必须为hex
if (value instanceof Integer) {
dataHex.append(DigitalUtils.algorism2Hex((Integer) value, structInfo.getLength() * 2));
} else if (value instanceof BigDecimal) {
dataHex.append(DigitalUtils.algorism2Hex(((BigDecimal) value).intValue(), structInfo.getLength() * 2));
} else if (value instanceof String) {
dataHex.append(value);
}
}


}
项目架构:

spring 注解、jdbc 连接池、membercache、netty4 。因项目比较大、如需要项目源码 可联系我 qq 451366323

猜你喜欢

转载自wangcunzhou.iteye.com/blog/2281653