Netty之网络编程数据编码
一、概况
我们在进行网络编程中会把各种数据转换为byte数据以便能在网络上传输,最常见的网络字节序——Little-Endian和Big-Endian,也让好多初进网络编程的新手摸不着头脑,还有按位或多位存储数据,按位或多位数据,BCD编码,ASCII编码,有符号数与无符号数的编码与解码等等。本篇博文所贴代码并不是最简洁最优化的,只是起到抛砖引玉的效果,不用像博主一样刚入门网络编程时经历那么的曲折,不过现在回想起来也是满满的收获。
二、代码实现
1. 编码工具类
1 package com.chansen.common.utils;
2
3
4 import com.chansen.common.enums.TypeEnum;
5 import io.netty.buffer.ByteBuf;
6 import io.netty.buffer.ByteBufAllocator;
7 import io.netty.buffer.ByteBufUtil;
8
9 import java.util.Arrays;
10 import java.util.Date;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.stream.Collectors;
14 import java.util.stream.IntStream;
15
16 /**
17 * 编码工具类
18 *
19 * @author CHANSEN
20 * @date
21 */
22 public final class EncodeUtils {
23
24
25 private EncodeUtils() {
26 }
27
28
29
30
31
32
33
34 /**
35 * 组装配置文件所配置的ByteBuf
36 *
37 * @param type 枚举类型字符串
38 * @param param 参数
39 * @param buf ByteBuf缓存域
40 * @param endian 字节序
41 */
42 public static void encode(String type, Object param,
43 ByteBuf buf, boolean endian) {
44
45 //类型枚举
46 final TypeEnum typeEnum = TypeEnum.match(type);
47 //根据不同的类型编码数据
48 switch (typeEnum) {
49 //有符号int
50 case TYPE_INT:
51 writeInt(param, buf, endian);
52 break;
53 //无符号int
54 case TYPE_UINT:
55 writeUnSignInt(param, buf, endian);
56 break;
57 //有符号short
58 case TYPE_SHORT:
59 writeShort(param, buf, endian);
60 break;
61 //无符号short
62 case TYPE_USHORT:
63 writeUnSignShort(param, buf, endian);
64 break;
65 //有符号byte
66 case TYPE_BYTE:
67 writeByte(param, buf);
68 break;
69 //无符号byte
70 case TYPE_UBYTE:
71 writeUnSignByte(param, buf);
72 break;
73 //字符串
74 case TYPE_STRING:
75 writeString(param, buf);
76 break;
77 //字符串时间
78 case TYPE_DATE_STRING:
79 writeDateString(param, buf);
80 break;
81 case TYPE_HEX_STRING:
82 writeHexString(param, buf);
83 break;
84 case TYPE_BIT:
85 writeBit(param, buf);
86 break;
87 case TYPE_MULTI_BIT:
88 writeMultiBit(param, buf);
89 break;
90 case TYPE_BCD8421:
91 writeBcd8421(param, buf);
92 break;
93 }
94 }
95
96 /**
97 * 组装ByteBuff
98 *
99 * @param type 枚举类型字符串
100 * @param param 参数
101 * @param rangeList 枚举范围
102 * @param buf ByteBuf缓存域
103 * @param endian 字节序
104 */
105 public static void encodeEnum(String type, Object param,
106 List<Object> rangeList,
107 ByteBuf buf, boolean endian) {
108 //枚举数据类型
109 final TypeEnum typeEnum = TypeEnum.match(type);
110
111 switch (typeEnum) {
112 case TYPE_ENUM_BYTE:
113 writeEnumByte(param, rangeList, buf);
114 break;
115 case TYPE_ENUM_INT:
116 writeEnumInt(param, rangeList, buf, endian);
117 break;
118 case TYPE_ENUM_STRING:
119 writeEnumString(param, rangeList, buf);
120 break;
121 case TYPE_ENUM_HEX_STRING:
122 writeEnumHexString(param, rangeList, buf);
123 break;
124 }
125
126 }
127
128 /**
129 * 写枚举Hex字符串
130 *
131 * @param obj 数据
132 * @param list 枚举范围
133 * @param buff ByteBuf缓存区
134 */
135 public static void writeEnumHexString(Object obj, List<Object> list, ByteBuf buff) {
136 for (Object object : list) {
137 if (object.toString().equals(obj.toString())) {
138 writeHexString(obj, buff);
139 }
140 }
141
142 }
143
144 /**
145 * 写枚举字符串
146 *
147 * @param obj 数据
148 * @param list 枚举范围
149 * @param buff ByteBuf缓存区
150 */
151 public static void writeEnumString(Object obj, List<Object> list, ByteBuf buff) {
152 for (Object object : list) {
153 if (object.toString().equals(obj.toString())) {
154 writeString(obj, buff);
155 }
156 }
157
158 }
159
160 /**
161 * 写枚举int
162 *
163 * @param obj 数据
164 * @param list 枚举范围
165 * @param buff ByteBuf缓存区
166 */
167 public static void writeEnumInt(Object obj, List<Object> list, ByteBuf buff, boolean endian) {
168 for (Object object : list) {
169 if (object.toString().equals(obj.toString())) {
170 writeInt(obj, buff, endian);
171 }
172 }
173
174 }
175
176 /**
177 * 写枚举byte
178 *
179 * @param obj 数据
180 * @param list 枚举范围
181 * @param buff ByteBuf缓存区
182 */
183 public static void writeEnumByte(Object obj, List<Object> list, ByteBuf buff) {
184 for (Object object : list) {
185 if (object.toString().equals(obj.toString())) {
186 writeByte(obj, buff);
187 }
188 }
189
190 }
191
192 /**
193 * 写字符串数据
194 *
195 * @param obj 值
196 * @param buf ByteBuf缓存区
197 */
198 public static void writeHexString(Object obj, ByteBuf buf) {
199 String value = (String) obj;
200 writeHexString(value, buf);
201 }
202
203 /**
204 * 写字符串数据
205 *
206 * @param value 值
207 * @param buf ByteBuf缓存区
208 */
209 public static void writeHexString(String value, ByteBuf buf) {
210 //value is hexDump
211 final byte[] bytes = ByteBufUtil.decodeHexDump(value);
212 buf.writeBytes(bytes);
213 }
214
215 /**
216 * 写时间字符串数据
217 *
218 * @param obj 值
219 * @param buf ByteBuf缓存区
220 */
221 public static void writeDateString(Object obj, ByteBuf buf) {
222 Date value = (Date) obj;
223 writeDateString(value, buf);
224 }
225
226 /**
227 * 写时间字符串数据
228 *
229 * @param obj 值
230 * @param buf ByteBuf缓存区
231 */
232 public static void writeDateString(Date obj, ByteBuf buf) {
233 String value = DateTimeUtils.getFormatDateTime(obj);
234 writeString(value, buf);
235 }
236
237 /**
238 * 写字符串数据
239 *
240 * @param obj 值
241 * @param buf ByteBuf缓存区
242 */
243 public static void writeString(Object obj, ByteBuf buf) {
244 String value = (String) obj;
245 writeString(value, buf);
246 }
247
248
249 /**
250 * 写字符串数据
251 *
252 * @param value 值
253 * @param buf ByteBuf缓存区
254 */
255 public static void writeString(String value, ByteBuf buf) {
256 final char[] valueChars = value.toCharArray();
257 if (valueChars.length > 0) {
258 for (char valueChar : valueChars) {
259 buf.writeByte(valueChar);
260 }
261 }
262 }
263
264 /**
265 * 写int数据
266 *
267 * @param obj 值
268 * @param buf ByteBuf缓存区
269 * @param endian 字节序
270 */
271 public static void writeInt(Object obj, ByteBuf buf, boolean endian) {
272 int m = (int) obj;
273 //小字节序
274 if (endian) {
275 buf.writeIntLE(m);
276 } else {
277 buf.writeInt(m);
278 }
279 }
280
281 /**
282 * 写无符号byte数据
283 *
284 * @param obj 值
285 * @param buf ByteBuf缓存区
286 */
287 public static void writeUnSignByte(Object obj, ByteBuf buf) {
288 int m = (int) obj;
289 writeUnSignByte(m, buf);
290 }
291
292 /**
293 * 写无符号byte数据
294 *
295 * @param m 值
296 * @param buf ByteBuf缓存区
297 */
298 public static void writeUnSignByte(int m, ByteBuf buf) {
299 writeUnSignByteBase(m, buf);
300 }
301
302 /**
303 * 写byte数据
304 *
305 * @param obj 值
306 * @param buf ByteBuf缓存区
307 */
308 public static void writeByte(Object obj, ByteBuf buf) {
309 int m = (int) obj;
310 assert m <= 127 && m >= -128;
311 buf.writeByte(m);
312 }
313
314 /**
315 * 写无符号short数据
316 *
317 * @param obj 值
318 * @param buf ByteBuf缓存区
319 * @param endian 字节序
320 */
321 public static void writeUnSignShort(Object obj, ByteBuf buf, boolean endian) {
322 int m = (int) obj;
323 assert m >= 0 && m <= 65535;
324 m &= 0x0FFFF;
325 writeShort(m, buf, endian);
326 }
327
328 /**
329 * 写short数据
330 *
331 * @param obj 值
332 * @param buf ByteBuf缓存区
333 * @param endian 字节序
334 */
335 public static void writeShort(Object obj, ByteBuf buf, boolean endian) {
336 int m = (short) obj;
337 //-32768~32767
338 assert m >= -32768 && m <= 32767;
339 writeShort(m, buf, endian);
340 }
341
342 /**
343 * 写无符号int数据
344 *
345 * @param obj 值
346 * @param buf ByteBuf缓存区
347 * @param endian 字节序
348 */
349 public static void writeUnSignInt(Object obj, ByteBuf buf, boolean endian) {
350 long m = (long) obj;
351 assert m >= 0 && m < 0x100000000L;
352 String hexString = Long.toHexString(m);
353 hexString = fullFillHexString(hexString);
354 final byte[] bytes = hexEncodeBytes(hexString, 4);
355 //小字节序
356 if (endian) {
357 final byte[] littleBytes = {bytes[3], bytes[2], bytes[1], bytes[0]};
358 buf.writeBytes(littleBytes);
359 } else {
360 buf.writeBytes(bytes);
361 }
362 }
363
364 /**
365 * hex字符串转byte数组
366 *
367 * @param hexString hex字符串
368 * @return byte数组
369 */
370 public static byte[] hexEncodeBytes(String hexString, int index) {
371 final byte[] bytes = ByteBufUtil.decodeHexDump(hexString);
372 int len = bytes.length;
373 byte[] bytesTmp = new byte[index];
374 if (len < index) {
375 byte[] bt = ByteBufUtil.decodeHexDump("00");
376 for (int i = 0; i < (index - len); i++) {
377 bytesTmp[i] = bt[0];
378 }
379 }
380
381 for (int j = bytes.length - 1; j >= 0; j--) {
382 bytesTmp[--index] = bytes[j];
383 }
384 return bytesTmp;
385 }
386
387 /**
388 * hex字符串补位处理
389 *
390 * @param hexString hex字符串
391 * @return hex字符串
392 */
393 public static String fullFillHexString(String hexString) {
394 int len = hexString.length();
395 int mold = len % 2;
396 return mold > 0 ? "0" + hexString : hexString;
397 }
398
399 /**
400 * 写short数据
401 *
402 * @param m 数据
403 * @param buf ByteBuf
404 * @param endian 字节序
405 */
406 public static void writeShort(int m, ByteBuf buf, boolean endian) {
407 //小字节序
408 if (endian) {
409 buf.writeShortLE(m);
410 } else {
411 //大字节序
412 buf.writeShort(m);
413 }
414 }
415
416 /**
417 * 写多bit位
418 *
419 * @param obj 参数
420 * @param buf ByteBuf
421 */
422 public static void writeMultiBit(Object obj, ByteBuf buf) {
423 int[] arr = (int[]) obj;
424 writeMultiBit(arr, buf);
425 }
426
427 /**
428 * 写多bit位
429 *
430 * @param arr 参数
431 * @param buff ByteBuf
432 */
433 public static void writeMultiBit(int[] arr, ByteBuf buff) {
434 int total = 0;
435 for (int i : arr) {
436 int j = 1 << i;
437 total += j;
438 }
439 writeBitBase(total, buff);
440 }
441
442 /**
443 * 写bit位
444 *
445 * @param obj 参数
446 * @param buff ByteBuf
447 */
448 public static void writeBit(Object obj, ByteBuf buff) {
449 int value = (int) obj;
450 writeBit(value, buff);
451 }
452
453 /**
454 * 位写bit
455 *
456 * @param buff ByteBuf数据缓存区
457 * @param bitIndex 置位索引
458 */
459 public static void writeBit(int bitIndex, ByteBuf buff) {
460 int i = 1 << bitIndex;
461 writeBitBase(i, buff);
462 }
463
464 /**
465 * 写bit位基础
466 *
467 * @param i 数据
468 * @param buff ByteBuf数据缓存区
469 */
470 private static void writeBitBase(int i, ByteBuf buff) {
471 //buff容量
472 final int capacity = buff.capacity();
473 assert capacity >= 1;
474 //255
475 if (i <= 0xff) {
476 int j = capacity;
477 --j;
478 fullFillBytes(buff, j);
479 buff.writeByte(i);
480 } else {
481 writeBitBaseMore(i, buff);
482 }
483 }
484
485 /**
486 * 写bit位基础较大值
487 *
488 * @param i 数据
489 * @param buff ByteBuf数据缓存区
490 */
491 private static void writeBitBaseMore(int i, ByteBuf buff) {
492 final int capacity = buff.capacity();
493 int j = capacity;
494 String hexString = Integer.toHexString(i);
495 hexString = fullFillHexString(hexString);
496 final byte[] bytes = ByteBufUtil.decodeHexDump(hexString);
497 assert bytes.length <= capacity;
498 j -= bytes.length;
499 fullFillBytes(buff, j);
500 buff.writeBytes(bytes);
501 }
502
503 /**
504 * 填充byte
505 *
506 * @param buff ByteBuf
507 * @param m 循环次数
508 */
509 private static void fullFillBytes(ByteBuf buff, int m) {
510 for (; m > 0; m--) {
511 buff.writeByte(0x00);
512 }
513 }
514
515 /**
516 * 写BCD码
517 * <p>
518 * 4位二进制数表示1位十进制数
519 * <p>
520 * 20200905
521 *
522 * @param obj 数据
523 * @param buff ByteBuf数据缓存区
524 */
525 public static void writeBcd8421(Object obj, ByteBuf buff) {
526 String value = (String) obj;
527 writeBcd8421(value, buff);
528 }
529
530 /**
531 * 写BCD码
532 * <p>
533 * 4位二进制数表示1位十进制数
534 * <p>
535 * 20200905
536 *
537 * @param bcdString 数据
538 * @param buff ByteBuf数据缓存区
539 */
540 public static void writeBcd8421(String bcdString, ByteBuf buff) {
541 assert bcdString.length() == buff.capacity() * 2;
542 final char[] chars = bcdString.toCharArray();
543 boolean flag = true;
544 int j = 0;
545 for (char ch : chars) {
546 int i = Integer.parseInt(ch + "");
547 if (flag) {
548 j = i << 4;
549 flag = false;
550 } else {
551 j += i;
552 writeUnSignByteBase(j, buff);
553 j = 0;
554 flag = true;
555 }
556 }
557 }
558
559 /**
560 * 写无符号数基础
561 *
562 * @param m 数据
563 * @param buff ByteBuf数据缓存区
564 */
565 private static void writeUnSignByteBase(int m, ByteBuf buff) {
566 assert m < 256 && m >= 0;
567 buff.writeByte(m);
568 }
569
570 }
2.数据类型枚举类
1 package com.chansen.common.enums;
2
3 /**
4 * 数据枚举
5 *
6 * @author CHANSEN
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项目是一个提供异步事件驱动网络应用框架和快速开发可维护的高性能高扩展性服务端和客户端协议工具集的成果.换句话说,Netty是一个NIO客户端服务端框架,它使得快速而简单的开 ...
- Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)
本文转载 https://www.javadoop.com 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.c ...
- Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型
本文转自:http://www.sohu.com/a/203838233_827544 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 ht ...
- Java网络编程与NIO详解2:JAVA NIO 一步步构建IO多路复用的请求模型
本文转载自:https://github.com/jasonGeng88/blog 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 http ...
- Java网络编程基础(Netty预备知识)
今天在家休息,闲来无事,写篇博客,陶冶下情操~~~ =================我是分割线================ 最近在重新学习Java网络编程基础,以便后续进行Netty的学习. 整 ...
- 用Netty开发中间件:网络编程基础
用Netty开发中间件:网络编程基础 <Netty权威指南>在网上的评价不是很高,尤其是第一版,第二版能稍好些?入手后快速翻看了大半本,不免还是想对<Netty权威指南(第二版)&g ...
- 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V1 -- 入门应用
网络编程 -- RPC实现原理 -- 目录 啦啦啦 V1——Netty入门应用 Class : NIOServerBootStrap package lime.pri.limeNio.netty.ne ...
- 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V2 -- 对象传输
网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- 使用序列化和反序列化在网络上传输对象:需要实现 java.io.Serializable 接口 只能传输( ByteBuf ...
- 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V3 -- 编码解码
网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- pipeline.addLast(io.netty.handler.codec.MessageToMessageCodec ...
随机推荐
- C++中的输入输出
update&fixed: 经过实测,io解绑在各大oj以及本地评测软件上都劣于scanf 所以在大数据的情况下还是推荐尽量使用scanf! ! ! ! 众所周知,C++自带了各种输入方式 比 ...
- Selenium文件上传问题
- Oracle适配问题解决
问题一:SQL 命令未正确结束 问题二:ORA-00907: 缺失右括号 问题三:mysql函数在Oracle中不适用 问题四:ORA-00936: 缺失表达式 问题五:No serializer f ...
- AutoGenerator自动生成代码
程序猿学社: https://blog.csdn.net/qq_16855077/article/details/105316295
- whlie do-whlie
switch语句 用于根据多个不同条件执行不同动作. while 循环 while循环基本语法: 条件初始化; while(条件表达式){ //条件表达式就是判 ...
- IEDA使用Tomcat后控制台中文出现乱码
如下图所示,Intellij IDEA显示中文为乱码, 根据Intellij IDEA控制台输出,Tomcat Log出现乱码,因此可以将问题定位到Tomcat上,具体解决方法: 第一步:打开Tom ...
- Centos 镜像文件下载
1. Centos 官网 https://www.centos.org 进入下载页面,选择下载的版本即可 不推荐在官网下载,因为官网上提供的下载地址很多是国外网站,下载太慢了 2. 阿里云Centos ...
- 如何将tensorflow1.x代码改写为pytorch代码(以图注意力网络(GAT)为例)
之前讲解了图注意力网络的官方tensorflow版的实现,由于自己更了解pytorch,所以打算将其改写为pytorch版本的. 对于图注意力网络还不了解的可以先去看看tensorflow版本的代码, ...
- do...while 循环
语法 C 语言中 do...while 循环的语法: do { statement(s); }while( condition ); 请注意,条件表达式出现在循环的尾部,所以循环中的 statemen ...
- DASH流媒体MPD中的segmentTemplate
SegmentTemplate利用MPD中的属性代入公式计算可以得到相关通配符的数值,来提供给客户端进行相关地址解析.相较于segmentList,使用 SegmentTemplate 的方式,能够很 ...