一、概况

  我们在进行网络编程中会把各种数据转换为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之网络编程数据编码的更多相关文章

  1. Netty与网络编程

    Netty什么? Netty项目是一个提供异步事件驱动网络应用框架和快速开发可维护的高性能高扩展性服务端和客户端协议工具集的成果.换句话说,Netty是一个NIO客户端服务端框架,它使得快速而简单的开 ...

  2. Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)

    本文转载 https://www.javadoop.com 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.c ...

  3. Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型

    本文转自:http://www.sohu.com/a/203838233_827544 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 ht ...

  4. Java网络编程与NIO详解2:JAVA NIO 一步步构建IO多路复用的请求模型

    本文转载自:https://github.com/jasonGeng88/blog 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 http ...

  5. Java网络编程基础(Netty预备知识)

    今天在家休息,闲来无事,写篇博客,陶冶下情操~~~ =================我是分割线================ 最近在重新学习Java网络编程基础,以便后续进行Netty的学习. 整 ...

  6. 用Netty开发中间件:网络编程基础

    用Netty开发中间件:网络编程基础 <Netty权威指南>在网上的评价不是很高,尤其是第一版,第二版能稍好些?入手后快速翻看了大半本,不免还是想对<Netty权威指南(第二版)&g ...

  7. 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V1 -- 入门应用

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V1——Netty入门应用 Class : NIOServerBootStrap package lime.pri.limeNio.netty.ne ...

  8. 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V2 -- 对象传输

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- 使用序列化和反序列化在网络上传输对象:需要实现 java.io.Serializable 接口 只能传输( ByteBuf ...

  9. 网络编程 -- RPC实现原理 -- Netty -- 迭代版本V3 -- 编码解码

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——Netty -- pipeline.addLast(io.netty.handler.codec.MessageToMessageCodec ...

随机推荐

  1. List集合对象去重及按属性去重的8种方法-java基础总结系列第六篇

    最近在写一些关于java基础的文章,但是我又不想按照教科书的方式去写知识点的文章,因为意义不大.基础知识太多了,如何将这些知识归纳总结,总结出优缺点或者是使用场景才是对知识的升华.所以我更想把java ...

  2. 一文搞懂WordPress建站

    文章首发于:https://zouwang.vip/ 日日夜夜的等待,WordPress建站教程终于来了.本篇文章适用于第一次建站的小白,帮助你从零搭建起一个属于自己的网站,既然是从零,那么我就会带着 ...

  3. 跟着尚硅谷系统学习Docker-【day04】

    day04-20200716   p18.docker容器数据卷   docker容器中的数据,做持久化. 容器关闭以后容器内的数据就没有了. 保存到数据库或者服务器宿主机里面.   作用:容器间可以 ...

  4. PHP的九个超全局变量

    1. 什么是超全局变量 PHP官网:超全局变量 超全局变量就是在全部作用域中始终可用的内置变量. 全局作用域.函数作用域都可以使用的PHP内置变量. 在函数或方法中无需执行 global $varia ...

  5. html基础:jquery的ajax获取form表单数据

    jq是对dom进行的再次封装.是一个js库,极大简化了js使用 jquery库在js文件中,包含了所有jquery函数,引用:<script src="jquery-1.11.1.mi ...

  6. linux 多进程

    Linux下的多进程编程初步 Linux下的多进程编程初步 多进程编程 1 Linux下进程的结构 2 Linux下的进程控制 21 僵尸进程 22 fork 23 exec 函数族 3 Linux下 ...

  7. [补题]匹配%#,%#之间的字符串重复%前的num遍

    题目 匹配%#,%#之间的字符串重复%前的num遍. 样例1: 3%acm#2%acm# 输出: acmacmacmacmacm 样例2: 3%2%acm## 输出: acmacmacmacmacm ...

  8. 血的教训!千万别在生产使用这些 redis 指令

    哎,最近小黑哥又双叒叕犯事了. 事情是这样的,前一段时间小黑哥公司生产交易偶发报错,一番排查下来最终原因是因为 Redis 命令执行超时. 可是令人不解的是,生产交易仅仅使用 Redis set 这个 ...

  9. JDK15真的来了,一起来看看它的新特性

    目录 简介 JDK15的新特性 JEP 385 Deprecate RMI Activation for Removal JEP 371 Hidden Classes JEP 339 Edwards- ...

  10. HTTP 【值得你看个究竟】

    我是一名程序员,我的主要编程语言是 Python,我更是一名 Web 开发人员,所以我必须要了解 HTTP,所以本篇文章就来带你从 HTTP 入门到进阶,看完让你有一种恍然大悟.醍醐灌顶的感觉. 认识 ...