一、概况
作为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相关的使用与心得。欢迎与大家一起探讨一起学习。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |