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 ...
随机推荐
- 跟着兄弟连系统学习Linux-【day03】
day03-20200529 p10.学习注意事项 linux严格区分大小写(与python有点像) Linux中所有内容都是通过文件形式保存,通过命令执行设置参数,写 ...
- 判断同名股票是否存在的MyBatis查询函数写法
在A股中,除非股票退市,六位的股票代号是永不变化的,而名称则可能变化,比如更换主业,更换金主,因经营不善而戴帽等,这时名称都会改变. 因此,从网页上爬取的实时股票信息,需要常常与存在本地数据库里的信息 ...
- Oracle WITH 语句 语法
With语句可以在查询中做成一个临时表/View,用意是在接下来的SQL中重用,而不需再写一遍. With Clause方法的优点: 增加了SQL的易读性,如果构造了多个子查询,结构会更清晰. 示例: ...
- 使用Java7提供的WatchService给目录添加新建文件监控
程序: import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Path; import ...
- docker基本操作及介绍
Docker 简介 Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目.它基于 Google 公司推出的 Go 语言实现.项目后来加入了 Linux ...
- 菜鸟电子面单对接技术方案(link)
一.背景 快递业务日新月异,收发快递是生活中不可缺少的一部分了,特别是做微商的商家,每天发送大量的快递.填写快递单已经成为过去式,快递小哥上门收件的时候,都使用手持的中端设备,再也不用客户填写快递单了 ...
- Vue 侦听器 watch
1. 侦听器 watch Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性 当属性发生改变时,自动触发属性对应的侦听器. 当需要在数据变化时执行异步或开销较大的操作时,这 ...
- 吴恩达《深度学习》-第五门课 序列模型(Sequence Models)-第二周 自然语言处理与词嵌入(Natural Language Processing and Word Embeddings)-课程笔记
第二周 自然语言处理与词嵌入(Natural Language Processing and Word Embeddings) 2.1 词汇表征(Word Representation) 词汇表示,目 ...
- 大写的服,看完这篇你还不懂RocketMQ算我输
目录 RocketMQ介绍 RocketMQ概念 为什么要用RocketMQ? 异步解耦 削峰填谷 分布式事务最终一致性 数据分发 RocketMQ架构 RocketMQ消息类型 普通消息 顺序消息 ...
- MySQL安装错误Couldn't find MySQL server
Starting MySQL ERROR! Couldn't find MySQL server (/usr/local/mysql/bin/mysqld_safe) 昨天rpm安装MySQL5.7后 ...