
6

Netty之数据解码 - 复姓江山
source link: https://www.cnblogs.com/inverseEntropy/p/17365544.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

作为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 * 读byte 107 * 108 * @param buff 编码数据 109 * @return 解码数据 110 */ 111 public static byte readByte(ByteBuf buff) { 112 return buff.readByte(); 113 } 114 115 /** 116 * 读无符号int 117 * 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 * 读int 129 * 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 * 读short 140 * 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 * 读无符号short 151 * 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 数据缓冲区ByteBuf 224 */ 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 * 读bit 236 * 237 * @param num 字节长度 238 * @param buff 数据缓冲区ByteBuf 239 * @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 * 读多位bit 260 * 261 * @param num 字节长度 262 * @param buff 数据缓冲区ByteBuf 263 * @return 二进制数据为1的索引数组 264 */ 265 public static int[] readMultiBit(int num, ByteBuf buff) { 266 ByteBuf buffCopy = buff.copy(0, num); 267 List<Integer> 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 * 收集索引存入List 305 * 306 * @param str byte二进制字符串 307 * @param size 剩余byte长度 308 * @param list 集合List 309 */ 310 private static void gatherIndexes(String str, int size, List<Integer> 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 数据缓冲区ByteBuf 328 * @return Bcd码解码数据 329 */ 330 public static String readBcd8421(int num, ByteBuf buff) { 331 return readHexString(num, buff); 332 } 333 }
2. 数据类型枚举类
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相关的使用与心得。欢迎与大家一起探讨一起学习。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK