首页
搜索 搜索

Netty之数据解码

博客园     2023-04-30 18:33:36


(资料图)

一、概况

作为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      * 读byte107      *108      * @param buff 编码数据109      * @return 解码数据110      */111     public static byte readByte(ByteBuf buff) {112         return buff.readByte();113     }114 115     /**116      * 读无符号int117      *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      * 读int129      *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      * 读short140      *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      * 读无符号short151      *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 数据缓冲区ByteBuf224      */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      * 读bit236      *237      * @param num  字节长度238      * @param buff 数据缓冲区ByteBuf239      * @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      * 读多位bit260      *261      * @param num  字节长度262      * @param buff 数据缓冲区ByteBuf263      * @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      * 收集索引存入List305      *306      * @param str  byte二进制字符串307      * @param size 剩余byte长度308      * @param list 集合List309      */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 数据缓冲区ByteBuf328      * @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相关的使用与心得。欢迎与大家一起探讨一起学习。

X 关闭

今日医药网版权所有Copyright ©  2023 All Rights Reserved.    备案号:沪ICP备2023005074号-40   联系邮箱:5 85 59 73 @qq.com