Netty之数据解码

一、概况

   作为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相关的使用与心得。欢迎与大家一起探讨一起学习。

发表评论

评论已关闭。

相关文章