• Netty之数据解码


    一、概况

       作为Java世界使用最广泛的网络通信框架Netty,其性能和效率是有目共睹的,好多大公司都在使用如苹果、谷歌、Facebook、Twitter、阿里巴巴等,所以不仅仅是因为Netty有高效的性能与效率,更重要的是:屏蔽了底层的复杂度,简单易懂的编程模型,适应更广泛的应用场景,以及活跃的开发者社区。
      本篇博客是作为Netty之数据编码的续篇,上一篇以抛砖引玉的方式讲解了怎么使用Netty的核心缓冲区ByteBuf怎么编码存储各种基本数据,本篇就是与之对应的怎么从Netty的数据容器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 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 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相关的使用与心得。欢迎与大家一起探讨一起学习。

  • 相关阅读:
    mysql主从和mycat读写分离的安装及验证
    【STM32】WWDG—窗口看门狗
    代码随想录算法训练营|五十七天
    《矛盾论》思考深度、高度
    数组转集合出现UnsupportedOperationException异常
    计算机网络 一、概述
    查杀Linux服务器病毒进程并对Linux中的文件描述符FD进行简单探索
    defer面试题,你能答对几题?
    备受以太坊基金会青睐的 Hexlink,构建亿级用户涌入 Web3的入口
    【linux】 mpstat 使用
  • 原文地址:https://www.cnblogs.com/inverseEntropy/p/17365544.html