Netty之数据编码
一、概况
我们在网络编程中会把各种数据转换为byte数组(即字节数组)以便能在网络上传输,最基本的如网络字节序(Little-Endian和Big-Endian),按位或多位数据编码与解码,IP地址的编码与解码,BCD编码与解码,ASCII编码与解码,16进制字符串的编码与解码,有符号数与无符号数的编码与解码等。本篇博文所贴代码并不是最简洁最优化的,只是起到抛砖引玉的效果,不用像博主一样刚入门网络编程时经历那么的曲折,少走些弯路,不过站在此刻回想正是经历了磨砺才会闪耀光泽。
二、代码实现
1. 编码工具类
1 package com.ethan.cws.common.utils; 2 3 4 import com.ethan.cws.common.enums.TypeEnum; 5 import io.netty.buffer.ByteBuf; 6 import io.netty.buffer.ByteBufAllocator; 7 import io.netty.buffer.ByteBufUtil; 8 9 import java.util.Arrays; 10 import java.util.Date; 11 import java.util.List; 12 import java.util.Map; 13 import java.util.stream.Collectors; 14 import java.util.stream.IntStream; 15 16 /** 17 * 编码工具类 18 * 19 * @author ethancws 20 * @date 21 */ 22 public final class EncodeUtils { 23 24 25 private EncodeUtils() { 26 } 27 28 29 30 31 32 33 34 /** 35 * 组装配置文件所配置的ByteBuf 36 * 37 * @param type 枚举类型字符串 38 * @param param 参数 39 * @param buf ByteBuf缓存域 40 * @param endian 字节序 41 */ 42 public static void encode(String type, Object param, 43 ByteBuf buf, boolean endian) { 44 45 //类型枚举 46 final TypeEnum typeEnum = TypeEnum.match(type); 47 //根据不同的类型编码数据 48 switch (typeEnum) { 49 //有符号int 50 case TYPE_INT: 51 writeInt(param, buf, endian); 52 break; 53 //无符号int 54 case TYPE_UINT: 55 writeUnSignInt(param, buf, endian); 56 break; 57 //有符号short 58 case TYPE_SHORT: 59 writeShort(param, buf, endian); 60 break; 61 //无符号short 62 case TYPE_USHORT: 63 writeUnSignShort(param, buf, endian); 64 break; 65 //有符号byte 66 case TYPE_BYTE: 67 writeByte(param, buf); 68 break; 69 //无符号byte 70 case TYPE_UBYTE: 71 writeUnSignByte(param, buf); 72 break; 73 //字符串 74 case TYPE_STRING: 75 writeString(param, buf); 76 break; 77 //字符串时间 78 case TYPE_DATE_STRING: 79 writeDateString(param, buf); 80 break; 81 case TYPE_HEX_STRING: 82 writeHexString(param, buf); 83 break; 84 case TYPE_BIT: 85 writeBit(param, buf); 86 break; 87 case TYPE_MULTI_BIT: 88 writeMultiBit(param, buf); 89 break; 90 case TYPE_BCD8421: 91 writeBcd8421(param, buf); 92 break; 93 } 94 } 95 96 /** 97 * 组装ByteBuff 98 * 99 * @param type 枚举类型字符串 100 * @param param 参数 101 * @param rangeList 枚举范围 102 * @param buf ByteBuf缓存域 103 * @param endian 字节序 104 */ 105 public static void encodeEnum(String type, Object param, 106 List<Object> rangeList, 107 ByteBuf buf, boolean endian) { 108 //枚举数据类型 109 final TypeEnum typeEnum = TypeEnum.match(type); 110 111 switch (typeEnum) { 112 case TYPE_ENUM_BYTE: 113 writeEnumByte(param, rangeList, buf); 114 break; 115 case TYPE_ENUM_INT: 116 writeEnumInt(param, rangeList, buf, endian); 117 break; 118 case TYPE_ENUM_STRING: 119 writeEnumString(param, rangeList, buf); 120 break; 121 case TYPE_ENUM_HEX_STRING: 122 writeEnumHexString(param, rangeList, buf); 123 break; 124 } 125 126 } 127 128 /** 129 * 写枚举Hex字符串 130 * 131 * @param obj 数据 132 * @param list 枚举范围 133 * @param buff ByteBuf缓存区 134 */ 135 public static void writeEnumHexString(Object obj, List<Object> list, ByteBuf buff) { 136 for (Object object : list) { 137 if (object.toString().equals(obj.toString())) { 138 writeHexString(obj, buff); 139 } 140 } 141 142 } 143 144 /** 145 * 写枚举字符串 146 * 147 * @param obj 数据 148 * @param list 枚举范围 149 * @param buff ByteBuf缓存区 150 */ 151 public static void writeEnumString(Object obj, List<Object> list, ByteBuf buff) { 152 for (Object object : list) { 153 if (object.toString().equals(obj.toString())) { 154 writeString(obj, buff); 155 } 156 } 157 158 } 159 160 /** 161 * 写枚举int 162 * 163 * @param obj 数据 164 * @param list 枚举范围 165 * @param buff ByteBuf缓存区 166 */ 167 public static void writeEnumInt(Object obj, List<Object> list, ByteBuf buff, boolean endian) { 168 for (Object object : list) { 169 if (object.toString().equals(obj.toString())) { 170 writeInt(obj, buff, endian); 171 } 172 } 173 174 } 175 176 /** 177 * 写枚举byte 178 * 179 * @param obj 数据 180 * @param list 枚举范围 181 * @param buff ByteBuf缓存区 182 */ 183 public static void writeEnumByte(Object obj, List<Object> list, ByteBuf buff) { 184 for (Object object : list) { 185 if (object.toString().equals(obj.toString())) { 186 writeByte(obj, buff); 187 } 188 } 189 190 } 191 192 /** 193 * 写字符串数据 194 * 195 * @param obj 值 196 * @param buf ByteBuf缓存区 197 */ 198 public static void writeHexString(Object obj, ByteBuf buf) { 199 String value = (String) obj; 200 writeHexString(value, buf); 201 } 202 203 /** 204 * 写字符串数据 205 * 206 * @param value 值 207 * @param buf ByteBuf缓存区 208 */ 209 public static void writeHexString(String value, ByteBuf buf) { 210 //value is hexDump 211 final byte[] bytes = ByteBufUtil.decodeHexDump(value); 212 buf.writeBytes(bytes); 213 } 214 215 /** 216 * 写时间字符串数据 217 * 218 * @param obj 值 219 * @param buf ByteBuf缓存区 220 */ 221 public static void writeDateString(Object obj, ByteBuf buf) { 222 Date value = (Date) obj; 223 writeDateString(value, buf); 224 } 225 226 /** 227 * 写时间字符串数据 228 * 229 * @param obj 值 230 * @param buf ByteBuf缓存区 231 */ 232 public static void writeDateString(Date obj, ByteBuf buf) { 233 String value = DateTimeUtils.getFormatDateTime(obj); 234 writeString(value, buf); 235 } 236 237 /** 238 * 写字符串数据 239 * 240 * @param obj 值 241 * @param buf ByteBuf缓存区 242 */ 243 public static void writeString(Object obj, ByteBuf buf) { 244 String value = (String) obj; 245 writeString(value, buf); 246 } 247 248 249 /** 250 * 写字符串数据 251 * 252 * @param value 值 253 * @param buf ByteBuf缓存区 254 */ 255 public static void writeString(String value, ByteBuf buf) { 256 final char[] valueChars = value.toCharArray(); 257 if (valueChars.length > 0) { 258 for (char valueChar : valueChars) { 259 buf.writeByte(valueChar); 260 } 261 } 262 } 263 264 /** 265 * 写int数据 266 * 267 * @param obj 值 268 * @param buf ByteBuf缓存区 269 * @param endian 字节序 270 */ 271 public static void writeInt(Object obj, ByteBuf buf, boolean endian) { 272 int m = (int) obj; 273 //小字节序 274 if (endian) { 275 buf.writeIntLE(m); 276 } else { 277 buf.writeInt(m); 278 } 279 } 280 281 /** 282 * 写无符号byte数据 283 * 284 * @param obj 值 285 * @param buf ByteBuf缓存区 286 */ 287 public static void writeUnSignByte(Object obj, ByteBuf buf) { 288 int m = (int) obj; 289 writeUnSignByte(m, buf); 290 } 291 292 /** 293 * 写无符号byte数据 294 * 295 * @param m 值 296 * @param buf ByteBuf缓存区 297 */ 298 public static void writeUnSignByte(int m, ByteBuf buf) { 299 writeUnSignByteBase(m, buf); 300 } 301 302 /** 303 * 写byte数据 304 * 305 * @param obj 值 306 * @param buf ByteBuf缓存区 307 */ 308 public static void writeByte(Object obj, ByteBuf buf) { 309 int m = (int) obj; 310 assert m <= 127 && m >= -128; 311 buf.writeByte(m); 312 } 313 314 /** 315 * 写无符号short数据 316 * 317 * @param obj 值 318 * @param buf ByteBuf缓存区 319 * @param endian 字节序 320 */ 321 public static void writeUnSignShort(Object obj, ByteBuf buf, boolean endian) { 322 int m = (int) obj; 323 assert m >= 0 && m <= 65535; 324 m &= 0x0FFFF; 325 writeShort(m, buf, endian); 326 } 327 328 /** 329 * 写short数据 330 * 331 * @param obj 值 332 * @param buf ByteBuf缓存区 333 * @param endian 字节序 334 */ 335 public static void writeShort(Object obj, ByteBuf buf, boolean endian) { 336 int m = (short) obj; 337 //-32768~32767 338 assert m >= -32768 && m <= 32767; 339 writeShort(m, buf, endian); 340 } 341 342 /** 343 * 写无符号int数据 344 * 345 * @param obj 值 346 * @param buf ByteBuf缓存区 347 * @param endian 字节序 348 */ 349 public static void writeUnSignInt(Object obj, ByteBuf buf, boolean endian) { 350 long m = (long) obj; 351 assert m >= 0 && m < 0x100000000L; 352 String hexString = Long.toHexString(m); 353 hexString = fullFillHexString(hexString); 354 final byte[] bytes = hexEncodeBytes(hexString, 4); 355 //小字节序 356 if (endian) { 357 final byte[] littleBytes = {bytes[3], bytes[2], bytes[1], bytes[0]}; 358 buf.writeBytes(littleBytes); 359 } else { 360 buf.writeBytes(bytes); 361 } 362 } 363 364 /** 365 * hex字符串转byte数组 366 * 367 * @param hexString hex字符串 368 * @return byte数组 369 */ 370 public static byte[] hexEncodeBytes(String hexString, int index) { 371 final byte[] bytes = ByteBufUtil.decodeHexDump(hexString); 372 int len = bytes.length; 373 byte[] bytesTmp = new byte[index]; 374 if (len < index) { 375 byte[] bt = ByteBufUtil.decodeHexDump("00"); 376 for (int i = 0; i < (index - len); i++) { 377 bytesTmp[i] = bt[0]; 378 } 379 } 380 381 for (int j = bytes.length - 1; j >= 0; j--) { 382 bytesTmp[--index] = bytes[j]; 383 } 384 return bytesTmp; 385 } 386 387 /** 388 * hex字符串补位处理 389 * 390 * @param hexString hex字符串 391 * @return hex字符串 392 */ 393 public static String fullFillHexString(String hexString) { 394 int len = hexString.length(); 395 int mold = len % 2; 396 return mold > 0 ? "0" + hexString : hexString; 397 } 398 399 /** 400 * 写short数据 401 * 402 * @param m 数据 403 * @param buf ByteBuf 404 * @param endian 字节序 405 */ 406 public static void writeShort(int m, ByteBuf buf, boolean endian) { 407 //小字节序 408 if (endian) { 409 buf.writeShortLE(m); 410 } else { 411 //大字节序 412 buf.writeShort(m); 413 } 414 } 415 416 /** 417 * 写多bit位 418 * 419 * @param obj 参数 420 * @param buf ByteBuf 421 */ 422 public static void writeMultiBit(Object obj, ByteBuf buf) { 423 int[] arr = (int[]) obj; 424 writeMultiBit(arr, buf); 425 } 426 427 /** 428 * 写多bit位 429 * 430 * @param arr 参数 431 * @param buff ByteBuf 432 */ 433 public static void writeMultiBit(int[] arr, ByteBuf buff) { 434 int total = 0; 435 for (int i : arr) { 436 int j = 1 << i; 437 total += j; 438 } 439 writeBitBase(total, buff); 440 } 441 442 /** 443 * 写bit位 444 * 445 * @param obj 参数 446 * @param buff ByteBuf 447 */ 448 public static void writeBit(Object obj, ByteBuf buff) { 449 int value = (int) obj; 450 writeBit(value, buff); 451 } 452 453 /** 454 * 位写bit 455 * 456 * @param buff ByteBuf数据缓存区 457 * @param bitIndex 置位索引 458 */ 459 public static void writeBit(int bitIndex, ByteBuf buff) { 460 int i = 1 << bitIndex; 461 writeBitBase(i, buff); 462 } 463 464 /** 465 * 写bit位基础 466 * 467 * @param i 数据 468 * @param buff ByteBuf数据缓存区 469 */ 470 private static void writeBitBase(int i, ByteBuf buff) { 471 //buff容量 472 final int capacity = buff.capacity(); 473 assert capacity >= 1; 474 //255 475 if (i <= 0xff) { 476 int j = capacity; 477 --j; 478 fullFillBytes(buff, j); 479 buff.writeByte(i); 480 } else { 481 writeBitBaseMore(i, buff); 482 } 483 } 484 485 /** 486 * 写bit位基础较大值 487 * 488 * @param i 数据 489 * @param buff ByteBuf数据缓存区 490 */ 491 private static void writeBitBaseMore(int i, ByteBuf buff) { 492 final int capacity = buff.capacity(); 493 int j = capacity; 494 String hexString = Integer.toHexString(i); 495 hexString = fullFillHexString(hexString); 496 final byte[] bytes = ByteBufUtil.decodeHexDump(hexString); 497 assert bytes.length <= capacity; 498 j -= bytes.length; 499 fullFillBytes(buff, j); 500 buff.writeBytes(bytes); 501 } 502 503 /** 504 * 填充byte 505 * 506 * @param buff ByteBuf 507 * @param m 循环次数 508 */ 509 private static void fullFillBytes(ByteBuf buff, int m) { 510 for (; m > 0; m--) { 511 buff.writeByte(0x00); 512 } 513 } 514 515 /** 516 * 写BCD码 517 * <p> 518 * 4位二进制数表示1位十进制数 519 * <p> 520 * 20200905 521 * 522 * @param obj 数据 523 * @param buff ByteBuf数据缓存区 524 */ 525 public static void writeBcd8421(Object obj, ByteBuf buff) { 526 String value = (String) obj; 527 writeBcd8421(value, buff); 528 } 529 530 /** 531 * 写BCD码 532 * <p> 533 * 4位二进制数表示1位十进制数 534 * <p> 535 * 20200905 536 * 537 * @param bcdString 数据 538 * @param buff ByteBuf数据缓存区 539 */ 540 public static void writeBcd8421(String bcdString, ByteBuf buff) { 541 assert bcdString.length() == buff.capacity() * 2; 542 final char[] chars = bcdString.toCharArray(); 543 boolean flag = true; 544 int j = 0; 545 for (char ch : chars) { 546 int i = Integer.parseInt(ch + ""); 547 if (flag) { 548 j = i << 4; 549 flag = false; 550 } else { 551 j += i; 552 writeUnSignByteBase(j, buff); 553 j = 0; 554 flag = true; 555 } 556 } 557 } 558 559 /** 560 * 写无符号数基础 561 * 562 * @param m 数据 563 * @param buff ByteBuf数据缓存区 564 */ 565 private static void writeUnSignByteBase(int m, ByteBuf buff) { 566 assert m < 256 && m >= 0; 567 buff.writeByte(m); 568 } 569 570 }
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之数据解码(https://www.cnblogs.com/inverseEntropy/p/17365544.html)
P.S.后期修改插入不了跳转链接。
不忘初心,不忘本谋