6

Netty之数据解码 - 复姓江山

 2 years ago
source link: https://www.cnblogs.com/inverseEntropy/p/17365544.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK