一、概况

  我们在进行网络编程中会把各种数据转换为byte数据以便能在网络上传输,最常见的网络字节序——Little-Endian和Big-Endian,也让好多初进网络编程的新手摸不着头脑,还有按位或多位存储数据,按位或多位读取数据,BCD编码,ASCII编码,有符号数与无符号数的编码与解码等等。本篇博文所贴代码并不是最简洁最优化的,只是起到抛砖引玉的效果,不用像博主一样刚入门网络编程时经历那么的曲折,不过现在回想起来也是满满的收获。

二、代码实现

1. 编码工具类

  1 package com.chansen.common.utils;
  2
  3
  4 import com.chansen.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 CHANSEN
 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.chansen.common.enums;
  2
  3 /**
  4  * 数据枚举
  5  *
  6  * @author CHANSEN
  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 }

后记,如果大家觉得不错,后期我会把数据解码的部分代码贴出来的。

10-14 00:18