一、概况

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

Netty之数据解码的更多相关文章

  1. netty之编解码

    1.netty的编码和解码,在数据传输的时候,考虑数据安全,数据完整性都是很有必要的.这里主要是介绍netty3和netty5的编解码方式.其实从StringEncoder和StringDecoder ...

  2. 在dubbo的一端,看Netty处理数据包,揭网络传输原理

    如今,我们想要开发一个网络应用,那是相当地方便.不过就是引入一个框架,然后设置些参数,然后写写业务代码就搞定了. 写业务代码自然很重要,但是你知道: 你的数据是怎么来的吗?通过网络传输过来的呗. 你知 ...

  3. 一文搞懂 Netty 发送数据全流程 | 你想知道的细节全在这里

    欢迎关注公众号:bin的技术小屋,如果大家在看文章的时候发现图片加载不了,可以到公众号查看原文 本系列Netty源码解析文章基于 4.1.56.Final版本 在<Netty如何高效接收网络数据 ...

  4. Netty入门系列(3) --使用Netty进行编解码的操作

    前言 何为编解码,通俗的来说,我们需要将一串文本信息从A发送到B并且将这段文本进行加工处理,如:A将信息文本信息编码为2进制信息进行传输.B接受到的消息是一串2进制信息,需要将其解码为文本信息才能正常 ...

  5. java架构之路-(netty专题)netty的编解码(出入战)与粘包拆包

    上次回归: 上次博客我们主要说了netty的基本使用,都是一些固定的模式去写的,我们只需要关注我们的拦截器怎么去写就可以了,然后我们用我们的基础示例,改造了一个简单的聊天室程序,可以看到内部加了一个S ...

  6. WebSocket帧数据 解码/转码

    数据从浏览器通过websocket发送给服务器的数据,是原始的帧数据,默认是被掩码处理过的,所以需要对其利用掩码进行解码. 从服务器发送给浏览器的数据是默认没有掩码处理的,只要符合一定结构就可以了.具 ...

  7. Android -- 获取摄像头帧数据解码

    由于Android下摄像头预览数据只能  ImageFormat.NV21 格式的,所以解码时要经过一翻周折. Camera mCamera = Camera.open(); Camera.Param ...

  8. Android 关于获取摄像头帧数据解码

    由于Android下摄像头预览数据只能  ImageFormat.NV21 格式的,所以解码时要经过一翻周折. Camera mCamera = Camera.open(); Camera.Param ...

  9. Netty返回数据丢包的问题之一

    这个问题是在一个群友做压力测试的时候发现的.使用客户端和netty创建一条连接,然后写了一个for循环不停的给服务器发送1500条信息,发现返回只有几百条.另外几百条不知道哪去了.查看代码,发现在服务 ...

  10. \x 开头编码的数据解码成中文

    在python里,直接decode('utf-8')即可 >>> "\xE5\x85\x84\xE5\xBC\x9F\xE9\x9A\xBE\xE5\xBD\x93 \xE ...

随机推荐

  1. 第二章 excel的快捷键操作

    本章介绍excel中部分常用的快捷键 1.文件类 工作簿操作:Ctrl + N 新建:Ctrl + w 关闭当前:Ctrl + S 保存 F12 当前另存为 Ctrl + p 打印当前 2.通用类 C ...

  2. docker&docker-compose安装

    一.docker安装 1.通过 uname -r 命令查看当前的内核版本,Docker 要求 CentOS 系统的内核版本高于 3.10 uname -r 2.查看系统是否安装过docker yum ...

  3. Centos 7 .Net core后台守护进程Supervisor教程

    ASP.NET Core应用程序发布linux在shell中运行是正常的.可一但shell关闭网站也就关闭了,所以要配置守护进程, 用的是Supervisor,本文主要记录配置的过程和过程遇到的问题 ...

  4. 按正斜线输出M*N的矩阵

    public static void outMatrix(int[][] array) { for(int row=0;row<array.length;row++) { int scolumn ...

  5. 发布订阅者模式 -- 简单的PubSub

    /** * 发布订阅者模式 * **/interface handle { [propName: string]: Function[]}class PubSub { private handles: ...

  6. RealWorldCTF渗透赛第二期复现-ctfshow

    比赛概述 开始时间:2023年3月10日15时 环境保留时间:72小时 环境重置时间:20分钟 官方wp链接:Docs (feishu.cn) [本次复现跟着官方WP进行,只做记录学习之用] 0x1 ...

  7. 《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(11)-Charles如何模拟弱网环境

    1.前言 张三:"我写的软件好奇怪啊,在网络好的时候一点问题也没有,但是信号差的时候明显卡顿,看来我只能一直蹲在卫生间.电梯或者地铁(信号差)调bug了". Charles:&qu ...

  8. 使用float进行比较问题处理

    float compare Abstract 使用float数据进行精确计算和比较,可能由于精度问题导致程序逻辑异常. Explanation 使用float数据进行比较,计算机表达double和fl ...

  9. 人脸关键点的应用场景及重难点解析丨Dev for Dev 专栏

    本文为「Dev for Dev 专栏」系列内容,作者为声网视频组 AI 算法工程师 周世付. 人脸检测.人脸关键点检测,是计算机视觉的基础算法.许多酷炫应用背后,例如美颜.贴纸.人脸驱动 avatar ...

  10. cost function 成本函数

    cost function 成本函数 cost function-成本函数 1.目标 :实现和探索具有一个变量的线性回归的成本函数. import numpy as np %matplotlib wi ...