一、概况

  我们在进行网络编程中会把各种数据转换为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. HDU—2021-发工资咯(水题,有点贪心的思想)

    作为杭电的老师,最盼望的日子就是每月的8号了,因为这一天是发工资的日子,养家糊口就靠它了,呵呵  但是对于学校财务处的工作人员来说,这一天则是很忙碌的一天,财务处的小胡老师最近就在考虑一个问题:如果每 ...

  2. HashMap源码解析、jdk7和8之后的区别、相关问题分析(多线程扩容带来的死循环)

    一.概览 HashMap<String, Integer> map = new HashMap<>(); 这个语句执行起来,在 jdk1.8 之前,会创建一个长度是 16 的 ...

  3. Java8 Functional(函数式接口)

    Functional 函数式(Functional)接口 只包含一个抽象方法的接口,称为函数式接口. 你可以通过 Lambda 表达式来创建该接口的对象.(若 Lambda 表达式抛出一个受检异常(即 ...

  4. MySQL互联网业务使用建议

    一.基础规范 表存储引擎必须使用InnoDB 表字符集默认使用utf8,必要时候使用utf8mb4 解读: (1)通用,无乱码风险,汉字3字节,英文1字节 (2)utf8mb4是utf8的超集,有存储 ...

  5. 内存管理初始化源码1:setup_arch

    源码声明:基于Linux kernel 3.08 1. 在kernel/arch/mips/kernel/head.S中会做一些特定硬件相关的初始化,然后会调用内核启动函数:start_kernel: ...

  6. matlab数字图像简单的加密方法

    图像加密的重要性可想而知,每个人都会有自己的小秘密,通过图像加密的方法可以保护自己的照片等的安全. 一般情况下,图像加密可以分为以下几个步骤: 1.选择图像加密算法 2.根据算法获取秘钥 3.根据保存 ...

  7. hystrix总结之请求批量执行

    hystrix可以将同一个命令的多次执行合并到一起执行. public class HelloWorldCommandCollapser extends HystrixCollapser<Lis ...

  8. 为什么我选择MySQL Workbench・一

    一.官方 官方提供的工具必然有其优势. MySQL Workbench有两个版本,社区版和商业版.社区版是免费的. 二.第一个选择 使用MySQL之前用的是SQL Server而微软的东西一般都使用微 ...

  9. GitLab集成kubernetes

    创建GitLab源码项目并上传示例代码 1. 创建GitLab源码项目 本示例中创建的GitLab源码项目地址为:https://gitee.com/SunHarvey/helloworld_java ...

  10. 你还不会ES的CUD吗?

    近端时间在搬砖过程中对es进行了操作,但是对es查询文档不熟悉,所以这两周都在研究es,简略看了<Elasticsearch权威指南>,摸摸鱼又是一天. es是一款基于Lucene的实时分 ...