(资料图片)
一、概况作为Java世界使用最广泛的网络通信框架Netty,其性能和效率是有目共睹的,好多大公司都在使用如苹果、谷歌、Facebook、Twitter、阿里巴巴等,所以不仅仅是因为Netty有高效的性能与效率,更重要的是:屏蔽了底层的复杂度,简单易懂的编程模型,适应更广泛的应用场景,以及活跃的开发者社区。 本篇博客是作为Netty之数据编码的续篇,上一篇以抛砖引玉的方式讲解了怎么使用Netty的核心缓冲区ByteBuf怎么编码存储各种基本数据,本篇就是与之对应的怎么从缓冲区ByteBuf中的编码数据解码出来,因为我们的Java代码中处理数据一般不是按照字节流来处理,所以需要解码恢复出数据然后再进行处理。
二、代码实现1. 解码工具类1 package com.ethan.cws.common.utils; 2 3 import com.ethan.cws.common.enums.TypeEnum; 4 import io.netty.buffer.ByteBuf; 5 import io.netty.buffer.ByteBufUtil; 6 import io.netty.util.CharsetUtil; 7 8 import java.util.ArrayList; 9 import java.util.Arrays; 10 import java.util.List; 11 12 /** 13 * 解码工具类 14 * 15 * @author ethancws 16 * @date 17 */ 18 public final class DecodeUtils { 19 20 /** 21 * FEP data数据文件后缀名 22 */ 23 public final static String FILE_SUFFIX_EXTEND = ".xml"; 24 25 /** 26 * 文件名 27 */ 28 public final static String FILE_NAME = "Filename"; 29 30 private DecodeUtils() { 31 32 } 33 34 /** 35 * 解码 36 * 37 * @param symbol 符号 38 * @param byteNum 字节数 39 * @param buff 数据 40 * @param type 枚举类型字符串 41 * @param endian 编码 42 * @return 解码数据 43 */ 44 public static Object decode(String symbol, int byteNum, ByteBuf buff, 45 String type, boolean endian) { 46 Object value = null; 47 //类型枚举 48 final TypeEnum typeEnum = TypeEnum.match(type); 49 switch (typeEnum) { 50 case TYPE_STRING: 51 case TYPE_ENUM_STRING: 52 case TYPE_DATE_STRING: 53 value = readString(byteNum, buff, symbol); 54 break; 55 case TYPE_HEX_STRING: 56 case TYPE_ENUM_HEX_STRING: 57 value = readHexString(byteNum, buff); 58 break; 59 case TYPE_USHORT: 60 value = readUnSignShort(buff, endian); 61 break; 62 case TYPE_SHORT: 63 value = readShort(buff, endian); 64 break; 65 case TYPE_INT: 66 case TYPE_ENUM_INT: 67 value = readInt(buff, endian); 68 break; 69 case TYPE_UINT: 70 value = readUnSignInt(buff, endian); 71 break; 72 case TYPE_BYTE: 73 case TYPE_ENUM_BYTE: 74 value = readByte(buff); 75 break; 76 case TYPE_UBYTE: 77 value = readUnSignByte(buff); 78 break; 79 case TYPE_BIT: 80 value = readBit(byteNum, buff); 81 break; 82 case TYPE_MULTI_BIT: 83 value = readMultiBit(byteNum, buff); 84 break; 85 case TYPE_BCD8421: 86 value = readBcd8421(byteNum, buff); 87 break; 88 89 } 90 91 return value; 92 } 93 94 /** 95 * 读无符号byte 96 * 97 * @param buff 编码数据 98 * @return 解码数据 99 */100 public static short readUnSignByte(ByteBuf buff) {101 byte by = buff.readByte();102 return (short) (by & 0x0FF);103 }104 105 /**106 * 读byte107 *108 * @param buff 编码数据109 * @return 解码数据110 */111 public static byte readByte(ByteBuf buff) {112 return buff.readByte();113 }114 115 /**116 * 读无符号int117 *118 * @param buff 编码数据119 * @param endian 字节序120 * @return 解码数据121 */122 public static long readUnSignInt(ByteBuf buff, boolean endian) {123 int intValue = endian ? buff.readIntLE() : buff.readInt();124 return intValue & 0x0FFFFFFFFL;125 }126 127 /**128 * 读int129 *130 * @param buff 编码数据131 * @param endian 字节序132 * @return 解码数据133 */134 public static int readInt(ByteBuf buff, boolean endian) {135 return endian ? buff.readIntLE() : buff.readInt();136 }137 138 /**139 * 读short140 *141 * @param buff 编码数据142 * @param endian 字节序143 * @return 解码数据144 */145 public static short readShort(ByteBuf buff, boolean endian) {146 return endian ? buff.readShortLE() : buff.readShort();147 }148 149 /**150 * 读无符号short151 *152 * @param buff 编码数据153 * @param endian 字节序154 * @return 解码数据155 */156 public static int readUnSignShort(ByteBuf buff, boolean endian) {157 short shortValue = endian ? buff.readShortLE() : buff.readShort();158 return shortValue & 0x0FFFF;159 }160 161 /**162 * 读Hex字符串163 *164 * @param num 字节长度165 * @param buff 编码数据166 * @return 字符串167 */168 public static String readHexString(int num, ByteBuf buff) {169 String value = ByteBufUtil.hexDump(buff, 0, num);170 readByteBuf(num, buff);171 return value;172 }173 174 /**175 * 读Hex字符串没有数据缓冲区偏移176 *177 * @param num 字节长度178 * @param buff 编码数据179 * @return 字符串180 */181 public static String readHexStringWithoutOffset(int num, ByteBuf buff) {182 return ByteBufUtil.hexDump(buff, 0, num);183 }184 185 /**186 * 获取文件名称187 *188 * @param fileName 字符189 * @return 文件名称190 */191 private static String acquireFileName(String fileName) {192 String fileSuffixExtend = FILE_SUFFIX_EXTEND;193 int index = fileName.lastIndexOf(fileSuffixExtend);194 index += fileSuffixExtend.length();195 fileName = fileName.substring(1, index);196 return fileName;197 }198 199 /**200 * 读字符串201 *202 * @param num 字节长度203 * @param buff 编码数据204 * @param symbol 编码标识205 * @return 字符串206 */207 public static String readString(int num, ByteBuf buff, String symbol) {208 final CharSequence charSequence = buff.getCharSequence(0, num, CharsetUtil.UTF_8);209 String value = charSequence.toString();210 if (FILE_NAME.equals(symbol)) {211 value = acquireFileName(value);212 }213 //移动读指针214 readByteBuf(num, buff);215 return value;216 }217 218 219 /**220 * 移动读指针221 *222 * @param num 移动字节数223 * @param buff 数据缓冲区ByteBuf224 */225 private static void readByteBuf(int num, ByteBuf buff) {226 assert num >= 1;227 if (num == 1) {228 buff.readByte();229 } else {230 buff.readBytes(num);231 }232 }233 234 /**235 * 读bit236 *237 * @param num 字节长度238 * @param buff 数据缓冲区ByteBuf239 * @return bit位索引240 */241 public static int readBit(int num, ByteBuf buff) {242 ByteBuf buffCopy = buff.copy(0, num);243 int index = 0;244 for (; num > 0; num--) {245 byte b = buffCopy.readByte();246 if (b != 0) {247 index += b / 2;248 --num;249 break;250 }251 }252 index += num * 8;253 //移动读指针254 readByteBuf(num, buff);255 return index;256 }257 258 /**259 * 读多位bit260 *261 * @param num 字节长度262 * @param buff 数据缓冲区ByteBuf263 * @return 二进制数据为1的索引数组264 */265 public static int[] readMultiBit(int num, ByteBuf buff) {266 ByteBuf buffCopy = buff.copy(0, num);267 List2. 数据类型枚举类list = new ArrayList<>();268 int size = num;269 final int fixedNum = num;270 for (; num > 0; num--) {271 size--;272 int b = readUnSignByte(buffCopy);273 if (b != 0) {274 String str = Integer.toBinaryString(b);275 str = fullFillByteString(str);276 gatherIndexes(str, size, list);277 }278 }279 //移动读指针280 readByteBuf(fixedNum, buff);281 return Arrays.stream(list.toArray(new Integer[0])).mapToInt(Integer::valueOf).toArray();282 }283 284 /**285 * 补全byte二进制8位字符串286 *287 * @param str 字符串288 * @return 补全8位后的字符串289 */290 private static String fullFillByteString(String str) {291 int len = 8;292 int length = str.length();293 if (length < 8) {294 StringBuilder strBuilder = new StringBuilder(str);295 for (int i = 0; i < len - length; i++) {296 strBuilder.insert(0, "0");297 }298 str = strBuilder.toString();299 }300 return str;301 }302 303 /**304 * 收集索引存入List305 *306 * @param str byte二进制字符串307 * @param size 剩余byte长度308 * @param list 集合List309 */310 private static void gatherIndexes(String str, int size, List list) {311 int len = 8, lenFixed = 8;312 for (char ch : str.toCharArray()) {313 int totalIndex = 0;314 len--;315 if (ch == 48) {316 continue;317 }318 totalIndex = len + size * lenFixed;319 list.add(totalIndex);320 }321 }322 323 /**324 * 读Bcd码325 *326 * @param num 字节长度327 * @param buff 数据缓冲区ByteBuf328 * @return Bcd码解码数据329 */330 public static String readBcd8421(int num, ByteBuf buff) {331 return readHexString(num, buff);332 }333 }
1 package com.ethan.cws.common.enums; 2 3 /** 4 * 数据枚举 5 * 6 * @author ethancws 7 * @date 8 */ 9 public enum TypeEnum { 10 /** 11 * 字符串 12 */ 13 TYPE_STRING("string"), 14 15 /** 16 * Binary-Coded Decimal 17 * bcd码 8421码 18 * 4位二进制数表示1位十进制数 19 */ 20 TYPE_BCD8421("bcd8421"), 21 /** 22 * 时间字符串 23 */ 24 TYPE_DATE_STRING("date_string"), 25 /** 26 * 枚举byte 27 */ 28 TYPE_ENUM_BYTE("enum|byte"), 29 30 /** 31 * 枚举int 32 */ 33 TYPE_ENUM_INT("enum|int"), 34 35 /** 36 * 枚举字符串 37 */ 38 TYPE_ENUM_STRING("enum|string"), 39 40 /** 41 * 枚举HEX字符串 42 */ 43 TYPE_ENUM_HEX_STRING("enum|hex_string"), 44 45 /** 46 * HEX字符串 47 */ 48 TYPE_HEX_STRING("hex_string"), 49 50 /** 51 * -2^31~2^31-1 52 * -2,147,483,648~2,147,483,647 53 */ 54 TYPE_INT("int"), 55 /** 56 * 0~2^32 57 * 0~4294967296L 58 */ 59 TYPE_UINT("uint"), 60 /** 61 * -2^15~2^15-1 62 * -32768~32767 63 */ 64 TYPE_SHORT("short"), 65 /** 66 * 0~65535 67 */ 68 TYPE_USHORT("ushort"), 69 /** 70 * -2^7~2^7-1 71 * -128~127 72 */ 73 TYPE_BYTE("byte"), 74 75 /** 76 * 0~256 77 */ 78 TYPE_UBYTE("ubyte"), 79 80 /** 81 * 多位同选 82 */ 83 TYPE_MULTI_BIT("multi_bit"), 84 /** 85 * 位 86 */ 87 TYPE_BIT("bit"); 88 89 private String val; 90 91 TypeEnum(String val) { 92 this.val = val; 93 } 94 95 96 /** 97 * 字符串匹配枚举类型 98 * 99 * @param value 字符串100 * @return 对应枚举101 */102 public static TypeEnum match(String value) {103 String str = "TYPE_";104 if (value.indexOf("|") > 0) {105 value = value.replace("|", "_");106 }107 str += value.toUpperCase();108 return valueOf(str);109 }110 111 112 }三、后记
随着对于Netty的理解和使用的深入,越来越对于Netty框架的痴迷,所以后面会不定期的更新Netty相关的使用与心得。欢迎与大家一起探讨一起学习。
标签: