Netty之網絡編程數據編碼

一、概況

  我們在進行網絡編程中會把各種數據轉換為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 }

後記,如果大家覺得不錯,後期我會把數據解碼的部分代碼貼出來的。