一、前言

  前面博客大部分介绍了基于EMQ中间件,通信协议使用的是MQTT,而传输的数据为纯文本数据,采用JSON格式。这种方式,大部分一看就知道是熟悉Web开发、软件开发的人喜欢用的方式。由于我也是做web软件开发的,也是比较喜欢这种方式。阿里的物联网平台,也是推荐这种方式。但是,但是做惯硬件开发,嵌入式开发就比较喜欢用裸TCP-Socket连接。采用的是二进制协议。基于此大部分应用场合为了兼容旧设备,就需要单独开发一个TCP服务器的网关。这里使用以前学过的,也是比较流行的Netty框架。

  话不多说,下面就开始了。

 二、协议

定义

描述

启动符‘@@’

(2字节)

数据包的第1、2字节,为固定值 64,64。

控制单元

业务流水号

(2字节)

数据包的第3、4字节。发送/确认模式下,业务流水号由发送端在发送新的数据包时按顺序加一,确认方按发送包的业务流水号返回;请求/应答模式下,业务流水号由请求端在发送新的请求命令时按顺序加一,应答方按请求包的业务流水号返回。低字节传输在前。业务流水号是一个2字节的正整数,由通信双方第一次建立网络连接时确定,初始值为0。业务流水号由业务发起方(业务发起方指发送/确认模式下的发送端或者请求/应答模式下的请求端)独立管理。业务发起方负责业务流水号的分配和回收,保证在业务存续期间业务流水号的唯一性。

协议版本号

(2字节)

协议版本号包含主版本号(第5字节)和用户版本号(第6字节)。主版本号为固定值1,用户版本号由用户自行定义。

时间标签

(6字节)

数据包的第7~12字节,为数据包发出的时间,具体定义表2。

源地址

(6字节)

数据包的第13~18字节,为数据包的源地址(监控中心或用户信息传输装置地址)。低字节传输在前。

目的地址

(6字节)

数据包的第19~24字节,为数据包的目的地址(监控中心或用户信息传输装置地址)。低字节传输在前。

应用数据单元长度

(2字节)

数据包的第25、26字节,为应用数据单元的长度,长度不应大于1024;低字节传输在前。

命令字节

(1字节)

数据包的第27字节,为控制单元的命令字节,具体定义见表3。

应用数据单元

(最大1024字节)

应用数据单元,基本格式见表3,对于确认/否认等命令包,此单元可为空。

校验和

(1字节)

控制单元中各字节数据(第3~第27字节)及应用数据单元的算术校验和,舍去8位以上的进位位后所形成的1字节二进制数。

结束符‘##’

(2字节)

为固定值 35,35。

  上面这个是本次需要处理的二进制数据格式。

三、代码部分

  3.0 Pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.1.1.RELEASE</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.wunaozai.iot.nettyplatform</groupId>
  12. <artifactId>NettyPlatform</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>IoTNettyPlatForm</name>
  15. <description>基于自定义协议,使用Netty,物联网通信平台</description>
  16.  
  17. <properties>
  18. <java.version>1.8</java.version>
  19. </properties>
  20.  
  21. <dependencies>
  22. <dependency>
  23. <groupId>org.springframework.boot</groupId>
  24. <artifactId>spring-boot-starter</artifactId>
  25. </dependency>
  26.  
  27. <!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
  28. <dependency>
  29. <groupId>io.netty</groupId>
  30. <artifactId>netty-all</artifactId>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.springframework.boot</groupId>
  34. <artifactId>spring-boot-configuration-processor</artifactId>
  35. <optional>true</optional>
  36. </dependency>
  37.  
  38. <!-- web项目必要的依赖 -->
  39. <dependency>
  40. <groupId>org.springframework.boot</groupId>
  41. <artifactId>spring-boot-starter-web</artifactId>
  42. </dependency>
  43.  
  44. <!-- 热启动devtools -->
  45. <dependency>
  46. <groupId>org.springframework.boot</groupId>
  47. <artifactId>spring-boot-devtools</artifactId>
  48. <optional>true</optional>
  49. <scope>true</scope>
  50. </dependency>
  51.  
  52. <dependency>
  53. <groupId>org.springframework.boot</groupId>
  54. <artifactId>spring-boot-starter-test</artifactId>
  55. <scope>test</scope>
  56. </dependency>
  57. </dependencies>
  58.  
  59. <build>
  60. <plugins>
  61. <plugin>
  62. <groupId>org.springframework.boot</groupId>
  63. <artifactId>spring-boot-maven-plugin</artifactId>
  64. <configuration>
  65. <fork>true</fork>
  66. </configuration>
  67. </plugin>
  68. </plugins>
  69. </build>
  70.  
  71. </project>

  3.1 SmartIotProtocol.java

  这个主要对通信协议模型进行简单封装

  1. package com.wunaozai.iot.nettyplatform.code;
  2.  
  3. /**
  4. * 自定义协议
  5. * @author Administrator
  6. * @see https://www.cnblogs.com/sidesky/p/6913109.html
  7. */
  8. public class SmartIotProtocol {
  9.  
  10. /**
  11. * 协议最短长度 30 字节
  12. */
  13. public static int MIN_LEN = 30;
  14.  
  15. /**
  16. * 数据包启动符号 @@
  17. */
  18. public static short START = 25700;
  19.  
  20. /**
  21. * 业务流水号
  22. */
  23. private short flowid;
  24. /**
  25. * 主版本
  26. */
  27. private byte version_major;
  28. /**
  29. * 次版本
  30. */
  31. private byte version_minor;
  32. /**
  33. * 秒
  34. */
  35. private byte second;
  36. /**
  37. * 分钟
  38. */
  39. private byte minute;
  40. /**
  41. * 小时
  42. */
  43. private byte hour;
  44. /**
  45. * 日
  46. */
  47. private byte day;
  48. /**
  49. * 月
  50. */
  51. private byte month;
  52. /**
  53. * 年
  54. */
  55. private byte year;
  56. /**
  57. * 数据包的源地址
  58. */
  59. private byte[] src;
  60. /**
  61. * 数据包的目的地址
  62. */
  63. private byte[] dest;
  64. /**
  65. * 应用数据单元长度 长度不应大于1024;低字节传输在前
  66. */
  67. private short data_len;
  68. /**
  69. * 命令字节 为控制单元的命令字节
  70. */
  71. private byte cmd;
  72. /**
  73. * 应用数据单元 对于确认/否认等命令包,此单元可为空
  74. */
  75. private byte[] data;
  76. /**
  77. * 校验和 控制单元中各字节数据(第3~第27字节)及应用数据单元的算术校验和,舍去8位以上的进位位后所形成的1字节二进制数
  78. */
  79. private byte checksum;
  80. /**
  81. * 协议结束符号 ##
  82. */
  83. public static short END = 13621;
  84.  
  85. /**
  86. * 打印调试信息
  87. */
  88. public void printDebugInfo(){
  89. System.out.println("---------完整数据包开始------------");
  90. System.out.println("|开始标志: " + printHexShort(START));
  91. System.out.println("|业务流水: " + printHexShort(flowid) + "\tFlowID:" + flowid);
  92. System.out.println("|协议版本: " + printHexByte(version_major) + printHexByte(version_minor));
  93. System.out.println("|时间标签: " + "20" + year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
  94. System.out.println("|源地址 : " + printHexBytes(src));
  95. System.out.println("|目的地址: " + printHexBytes(dest));
  96. System.out.println("|数据长度: " + data_len);
  97. System.out.println("|命令字节: " + printHexByte(cmd));
  98. System.out.println("|应用数据: " + printHexBytes(data));
  99. System.out.println("|校验字节: " + printHexByte(checksum));
  100. System.out.println("|结束标志: " + printHexShort(END));
  101. System.out.println("---------------------------------");
  102. }
  103. private String printHexByte(byte b){
  104. return String.format("%02X", b);
  105. }
  106. private String printHexBytes(byte[] bytes){
  107. String str = "";
  108. for(int i=0; i<bytes.length; i++){
  109. str += String.format("%02X", bytes[i]);
  110. }
  111. return str;
  112. }
  113. private String printHexShort(int s){
  114. byte[] bytes = hexShort(s);
  115. return printHexBytes(bytes);
  116. }
  117. private byte[] hexShort(int s){
  118. byte[] bytes = new byte[2];
  119. bytes[0] = (byte)((s << 24) >> 24);
  120. bytes[1] = (byte)((s << 16) >> 24);
  121. return bytes;
  122. }
  123. private byte[] hexInt(int n){
  124. byte[] bytes = new byte[4];
  125. bytes[3] = (byte) ((n ) >> 24);
  126. bytes[2] = (byte) ((n << 8) >> 24);
  127. bytes[1] = (byte) ((n << 16) >> 24);
  128. bytes[0] = (byte) ((n << 24) >> 24);
  129. return bytes;
  130. }
  131.  
  132. public short getFlowid() {
  133. return flowid;
  134. }
  135. public void setFlowid(short flowid) {
  136. this.flowid = flowid;
  137. }
  138. public byte getVersion_major() {
  139. return version_major;
  140. }
  141. public void setVersion_major(byte version_major) {
  142. this.version_major = version_major;
  143. }
  144. public byte getVersion_minor() {
  145. return version_minor;
  146. }
  147. public void setVersion_minor(byte version_minor) {
  148. this.version_minor = version_minor;
  149. }
  150. public byte getSecond() {
  151. return second;
  152. }
  153. public void setSecond(byte second) {
  154. this.second = second;
  155. }
  156. public byte getMinute() {
  157. return minute;
  158. }
  159. public void setMinute(byte minute) {
  160. this.minute = minute;
  161. }
  162. public byte getHour() {
  163. return hour;
  164. }
  165. public void setHour(byte hour) {
  166. this.hour = hour;
  167. }
  168. public byte getDay() {
  169. return day;
  170. }
  171. public void setDay(byte day) {
  172. this.day = day;
  173. }
  174. public byte getMonth() {
  175. return month;
  176. }
  177. public void setMonth(byte month) {
  178. this.month = month;
  179. }
  180. public byte getYear() {
  181. return year;
  182. }
  183. public void setYear(byte year) {
  184. this.year = year;
  185. }
  186. public byte[] getSrc() {
  187. return src;
  188. }
  189. public void setSrc(byte[] src) {
  190. this.src = src;
  191. }
  192. public byte[] getDest() {
  193. return dest;
  194. }
  195. public void setDest(byte[] dest) {
  196. this.dest = dest;
  197. }
  198. public short getData_len() {
  199. return data_len;
  200. }
  201. public void setData_len(short data_len) {
  202. this.data_len = data_len;
  203. }
  204. public byte getCmd() {
  205. return cmd;
  206. }
  207. public void setCmd(byte cmd) {
  208. this.cmd = cmd;
  209. }
  210. public byte[] getData() {
  211. return data;
  212. }
  213. public void setData(byte[] data) {
  214. this.data = data;
  215. }
  216. public byte getChecksum() {
  217. return checksum;
  218. }
  219. public void setChecksum(byte checksum) {
  220. this.checksum = checksum;
  221. }
  222.  
  223. }

  3.2 SmartIotDecoder.java

  解码器,这个是本次的重点,这个解码器最主要是解决TCP粘包拆包问题,如果有不清楚的,要重点理解一下。

  1. package com.wunaozai.iot.nettyplatform.code;
  2.  
  3. import java.util.List;
  4.  
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7.  
  8. import io.netty.buffer.ByteBuf;
  9. import io.netty.channel.ChannelHandlerContext;
  10. import io.netty.handler.codec.ByteToMessageDecoder;
  11.  
  12. /**
  13. * 自定义协议解析
  14. * @author Administrator
  15. *
  16. */
  17. public class SmartIotDecoder extends ByteToMessageDecoder {
  18.  
  19. private static final Logger log = LoggerFactory.getLogger(SmartIotDecoder.class);
  20.  
  21. @Override
  22. protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
  23. log.debug("启动解码器...");
  24. log.debug("目前数据缓存大小: " + buffer.readableBytes());
  25. // 刻度长度必须大于基本最小长度
  26. if(buffer.readableBytes() >= SmartIotProtocol.MIN_LEN){
  27. log.debug("符合最小长度,进行解析");
  28. //防止socket字节流攻击、客户端传来的数据过大,这里需要对数据进行过滤掉
  29. if(buffer.readableBytes() >= 4096){
  30. buffer.skipBytes(buffer.readableBytes());
  31. return ;
  32. }
  33.  
  34. //记录包头开始位置
  35. int beginReader = 0;
  36. while(true){
  37. beginReader = buffer.readerIndex(); //记录包头开始位置
  38. buffer.markReaderIndex(); //标记包头开始index
  39. //读取协议开始标志
  40. if(buffer.readShort() == SmartIotProtocol.START){
  41. break; //如果是开始标记,那么就结束查找
  42. }
  43.  
  44. //如果找不到包头,这里要一个一个字节跳过
  45. buffer.resetReaderIndex();
  46. buffer.readByte();
  47.  
  48. //当跳过后,如果数据包又不符合长度的,结束本次协议解析
  49. if(buffer.readableBytes() < SmartIotProtocol.MIN_LEN){
  50. return ;
  51. }
  52. }
  53.  
  54. short flowid = buffer.readShort();
  55. byte version_major = buffer.readByte();
  56. byte version_minor = buffer.readByte();
  57. byte second = buffer.readByte();
  58. byte minute = buffer.readByte();
  59. byte hour = buffer.readByte();
  60. byte day = buffer.readByte();
  61. byte month = buffer.readByte();
  62. byte year = buffer.readByte();
  63. byte[] src = new byte[6];
  64. src[0] = buffer.readByte();
  65. src[1] = buffer.readByte();
  66. src[2] = buffer.readByte();
  67. src[3] = buffer.readByte();
  68. src[4] = buffer.readByte();
  69. src[5] = buffer.readByte();
  70. byte[] dest = new byte[6];
  71. dest[0] = buffer.readByte();
  72. dest[1] = buffer.readByte();
  73. dest[2] = buffer.readByte();
  74. dest[3] = buffer.readByte();
  75. dest[4] = buffer.readByte();
  76. dest[5] = buffer.readByte();
  77. short data_len = buffer.readShort();
  78. if(buffer.readableBytes() < data_len + 4){
  79. //还原读指针
  80. buffer.readerIndex(beginReader);
  81. return ;
  82. }
  83. byte cmd = buffer.readByte();
  84. byte[] data = null;
  85. if(data_len > 0){
  86. //读取应用数据单元
  87. data = new byte[data_len];
  88. buffer.readBytes(data);
  89. }
  90.  
  91. byte checksum = buffer.readByte();
  92. short end = buffer.readShort();
  93.  
  94. if(end == SmartIotProtocol.END){
  95. log.debug("完成解析,并输出.");
  96. SmartIotProtocol iot = new SmartIotProtocol();
  97. iot.setFlowid(flowid);
  98. iot.setVersion_major(version_major);
  99. iot.setVersion_minor(version_minor);
  100. iot.setSecond(second);
  101. iot.setMinute(minute);
  102. iot.setHour(hour);
  103. iot.setDay(day);
  104. iot.setMonth(month);
  105. iot.setYear(year);
  106. iot.setSrc(src);
  107. iot.setDest(dest);
  108. iot.setData_len(data_len);
  109. iot.setCmd(cmd);
  110. if(data_len > 0){
  111. iot.setData(data);
  112. }else{
  113. iot.setData(null);
  114. }
  115. iot.setChecksum(checksum);
  116. out.add(iot);
  117. }
  118. }
  119. }
  120.  
  121. }

  3.3 SmartIotEncoder.java

  相对于解码,这个编码器,就相对简单了,按照协议,一个byte一本byte进行发送即可。

  1. package com.wunaozai.iot.nettyplatform.code;
  2.  
  3. import io.netty.buffer.ByteBuf;
  4. import io.netty.channel.ChannelHandlerContext;
  5. import io.netty.handler.codec.MessageToByteEncoder;
  6.  
  7. /**
  8. * 自定义协议数据解析
  9. * @author Administrator
  10. *
  11. */
  12. public class SmartIotEncoder extends MessageToByteEncoder<SmartIotProtocol> {
  13.  
  14. @Override
  15. protected void encode(ChannelHandlerContext ctx, SmartIotProtocol msg, ByteBuf out) throws Exception {
  16. //写入消息SmartIot具体内容
  17. out.writeShort(SmartIotProtocol.START);
  18. out.writeShort(msg.getFlowid());
  19. out.writeByte(msg.getVersion_major());
  20. out.writeByte(msg.getVersion_minor());
  21. out.writeByte(msg.getSecond());
  22. out.writeByte(msg.getMinute());
  23. out.writeByte(msg.getHour());
  24. out.writeByte(msg.getDay());
  25. out.writeByte(msg.getMonth());
  26. out.writeByte(msg.getYear());
  27. out.writeBytes(msg.getSrc());
  28. out.writeBytes(msg.getDest());
  29. out.writeShort(msg.getData_len());
  30. out.writeByte(msg.getCmd());
  31. out.writeBytes(msg.getData());
  32. out.writeByte(msg.getChecksum());
  33. out.writeShort(SmartIotProtocol.END);
  34. }
  35.  
  36. }

  3.4 SmartIotHandler.java

  这个是工程里面的主要业务操作类,用户Handler处理所有业务操作,这里也可以理解为是一个入口、网关。所有命令都从这里进行分发到子模块。

  1. package com.wunaozai.iot.nettyplatform.code;
  2.  
  3. import java.net.InetSocketAddress;
  4.  
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7.  
  8. import io.netty.channel.ChannelHandlerContext;
  9. import io.netty.channel.SimpleChannelInboundHandler;
  10.  
  11. /**
  12. * 服务Handler 处理
  13. * @author Administrator
  14. *
  15. */
  16. public class SmartIotHandler extends SimpleChannelInboundHandler<SmartIotProtocol> {
  17.  
  18. private static final Logger log = LoggerFactory.getLogger(SmartIotHandler.class);
  19.  
  20. @Override
  21. protected void channelRead0(ChannelHandlerContext ctx, SmartIotProtocol iot)
  22. throws Exception {
  23. log.info("收到设备数据包: " + iot.getFlowid());
  24. iot.printDebugInfo();
  25. ctx.write("ok");
  26. }
  27.  
  28. @Override
  29. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  30. InetSocketAddress socket = (InetSocketAddress) ctx.channel().remoteAddress();
  31. String ip = socket.getAddress().getHostAddress();
  32. log.info("收到客户端IP: " + ip);
  33. }
  34.  
  35. @Override
  36. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  37. ctx.close();
  38. }
  39. }

  3.5 NettyServerInitializer.java

  这个就是初始化本次Netty框架中,使用的编解码器,还有对应的处理类。

  1. package com.wunaozai.iot.nettyplatform.config;
  2.  
  3. import com.wunaozai.iot.nettyplatform.code.SmartIotDecoder;
  4. import com.wunaozai.iot.nettyplatform.code.SmartIotEncoder;
  5. import com.wunaozai.iot.nettyplatform.code.SmartIotHandler;
  6.  
  7. import io.netty.channel.ChannelInitializer;
  8. import io.netty.channel.ChannelPipeline;
  9. import io.netty.channel.socket.SocketChannel;
  10.  
  11. /**
  12. * 服务器初始化
  13. * @author Administrator
  14. *
  15. */
  16. public class NettyServerInitializer extends ChannelInitializer<SocketChannel> {
  17.  
  18. @Override
  19. protected void initChannel(SocketChannel ch) throws Exception {
  20. // ChannelPipeline pipeline = ch.pipeline();
  21. // //自定义切割符
  22. // //ByteBuf delimiter = Unpooled.copiedBuffer(new byte[] {16});
  23. // ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
  24. //
  25. // pipeline.addLast(new DelimiterBasedFrameDecoder(8192, delimiter));
  26. // pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
  27. // pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
  28. // pipeline.addLast(new NettyServerHandler());
  29.  
  30. ChannelPipeline pipeline = ch.pipeline();
  31. //添加自定义编解码器
  32. pipeline.addLast(new SmartIotEncoder());
  33. pipeline.addLast(new SmartIotDecoder());
  34. //处理网络IO
  35. pipeline.addLast(new SmartIotHandler());
  36. }
  37.  
  38. }

  3.6 NettyServer.java

  Netty功能的入口类,所有Netty框架初始化步骤都在这里进行简单处理。

  1. package com.wunaozai.iot.nettyplatform.config;
  2.  
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.stereotype.Component;
  6.  
  7. import io.netty.bootstrap.ServerBootstrap;
  8. import io.netty.channel.ChannelFuture;
  9. import io.netty.channel.ChannelOption;
  10. import io.netty.channel.EventLoopGroup;
  11. import io.netty.channel.nio.NioEventLoopGroup;
  12. import io.netty.channel.socket.nio.NioServerSocketChannel;
  13. import io.netty.handler.logging.LogLevel;
  14. import io.netty.handler.logging.LoggingHandler;
  15.  
  16. /**
  17. * Netty 服务器
  18. * @author Administrator
  19. *
  20. */
  21. @Component
  22. public class NettyServer {
  23.  
  24. private static final Logger log = LoggerFactory.getLogger(NettyServer.class);
  25.  
  26. private int port = 7777;
  27.  
  28. public void run(){
  29. EventLoopGroup bossGroup = new NioEventLoopGroup();
  30. EventLoopGroup workerGroup = new NioEventLoopGroup();
  31. try {
  32. ServerBootstrap serverBootstrap = new ServerBootstrap();
  33. serverBootstrap.group(bossGroup, workerGroup);
  34. serverBootstrap.channel(NioServerSocketChannel.class);
  35. serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);
  36. serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
  37. serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
  38. serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
  39. serverBootstrap.childHandler(new NettyServerInitializer());
  40. // 绑定端口,开始接收进来的连接
  41. ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
  42. log.info("netty服务启动: [port:" + port + "]");
  43. // 等待服务器socket关闭
  44. channelFuture.channel().closeFuture().sync();
  45. } catch (Exception e) {
  46. log.error("Netty 服务启动失败: " + e.getMessage());
  47. }finally {
  48. bossGroup.shutdownGracefully();
  49. workerGroup.shutdownGracefully();
  50. }
  51. }
  52. }

  3.7 IotNettyPlatFormApplication.java

  这个是Spring Boot项目的入口函数。在这里调用Netty的入口函数。

  1. package com.wunaozai.iot.nettyplatform;
  2.  
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.boot.SpringApplication;
  6. import org.springframework.boot.autoconfigure.SpringBootApplication;
  7. import org.springframework.context.annotation.ComponentScan;
  8. import org.springframework.web.servlet.config.annotation.EnableWebMvc;
  9.  
  10. import com.wunaozai.iot.nettyplatform.config.NettyServer;
  11.  
  12. @SpringBootApplication
  13. public class IoTNettyPlatFormApplication {
  14.  
  15. private static final Logger log = LoggerFactory.getLogger(IoTNettyPlatFormApplication.class);
  16.  
  17. public static void main(String[] args) {
  18. SpringApplication.run(IoTNettyPlatFormApplication.class, args);
  19. run();
  20. }
  21.  
  22. private static NettyServer nettyServer = new NettyServer();
  23.  
  24. private static void run(){
  25. Thread thread = new Thread(new Runnable() {
  26. @Override
  27. public void run() {
  28. nettyServer.run();
  29. }
  30. });
  31. thread.start();
  32. }
  33.  
  34. }

  我这里通过在@SpringBootApplication 这里调用NettyServer。同时还有其他方式:

  1) 通过实现ApplicationListener

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import org.springframework.context.ApplicationListener;
  4. import org.springframework.context.event.ContextRefreshedEvent;
  5. import org.springframework.stereotype.Component;
  6.  
  7. /**
  8. * 项目初始化
  9. * @author wunaozai
  10. * @date 2018-05-24
  11. */
  12. @Component
  13. public class OnStartListener implements ApplicationListener<ContextRefreshedEvent> {
  14.  
  15. private static final Logger log = LoggerFactory.getLogger(OnStartListener.class);
  16.  
  17. @Override
  18. public void onApplicationEvent(ContextRefreshedEvent arg0) {
  19. log.info("Run on Start Listener.");
  20. }
  21.  
  22. }

  2) 通过实现CommandLineRunner

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import org.springframework.boot.CommandLineRunner;
  4. import org.springframework.core.annotation.Order;
  5. import org.springframework.stereotype.Component;
  6.  
  7. /**
  8. * 项目启动时初始化资源<br>
  9. * 如 一些初始化操作,提前加载加密证书,初始化线程池等
  10. * @author wunaozai
  11. * @date 2018-05-24
  12. */
  13. @Component
  14. @Order(value = 1) //执行顺序
  15. public class Runner implements CommandLineRunner {
  16.  
  17. private static final Logger log = LoggerFactory.getLogger(Runner.class);
  18.  
  19. @Override
  20. public void run(String... args) throws Exception {
  21. log.info("The Runner start to Initialize.");
  22. }
  23.  
  24. }

三、协议测试

四、简单架构

  由于引入了自定义协议,所以需要对原先的流程进行简单的改造,下面这个图是某项目的架构图。

参考资料:

  https://www.cnblogs.com/sidesky/p/6913109.html

架构系列: https://www.cnblogs.com/wunaozai/p/8067577.html

本文地址: https://www.cnblogs.com/wunaozai/p/11403015.html

物联网架构成长之路(35)-利用Netty解析物联网自定义协议的更多相关文章

  1. 物联网架构成长之路(47)-利用GitLab实现CI持续集成

    0.前言 前段时间,考虑到要练习部署一套CI/CD的系统.一开始考虑到Jenkins,随着这两天的了解,发现最新版的GitLab已经提供有CI/CD集成了.所以本次博客,干脆一步到位,直接用GitLa ...

  2. 物联网架构成长之路(25)-Docker构建项目用到的镜像1

    0. 前言 现在项目处于初级阶段,按照规划,先构建几个以后可能会用到的Image,并上传到阿里云的Docker仓库.以后博客中用到的Image,大部分都会用到这几个基础的Image,构建一个简单的物联 ...

  3. 物联网架构成长之路(31)-EMQ基于HTTP权限验证

    看过之前的文章就知道,我之前是通过搞插件,或者通过里面的MongoDB来进行EMQ的鉴权登录和权限验证.但是前段时间发现,还是通过HTTP WebHook 方式来调用鉴权接口比较适合实际使用.还是实现 ...

  4. 物联网架构成长之路(24)-Docker练习之Compose容器编排

    0.前言 一开始学的之后,是想一步到位直接上Kubernetes(K8s)的,后面没想到,好像有点复杂,有些概念不是很懂.因此学习东西还是要循序渐进,慢慢来.先了解单机编排技术Docker Compo ...

  5. 物联网架构成长之路(33)-EMQ数据存储到influxDB

    一.前言 时隔一年半,技术变化特别快,学习也要跟上才行.以前写过EMQ数据转存问题,当时用了比较笨的方法,通过写插件的方式,把MQTT里面的数据发送到数据库进行存储.当时也是为了学习erlang和em ...

  6. 物联网架构成长之路(29)-Jenkins环境搭建

    0. 说明 哈哈,前面中间插入了一篇Eclipse增加Git插件,在此之前真的没有用过GIT. 1. 运行Jenkins 这里为了方便,还是用Docker方式安装,由于这个是标准的war报,不对Doc ...

  7. 物联网架构成长之路(16)-SpringCloud从入门到吹水

    1.前言 Spring Cloud 现在比较流行,版本更新也是蛮快的,网上资料也是很多.很多参考网上资料就可以学到了.这里给个 http://blog.csdn.net/forezp/article/ ...

  8. 物联网架构成长之路(22)-Docker练习之Etcd服务搭建

    0. 前言 时隔多日,前段时间忙完一个可有可无的项目后,又进入摸鱼时间,没有办法,非互联网公司,就是闲得蛋疼.又开始了自学之路.以前入门过Docker,然后又很久没有看了,最近重新看了一下,推荐一下这 ...

  9. 物联网架构成长之路(32)-SpringBoot集成MQTT客户端

    一.前言 这里虽然是说MQTT客户端.其实对于服务器来说,这里的一个具有超级权限的MQTT客户端,就可以做很多事情.比如手机APP或者网页或者第三方服务需要发送数据到设备,但是这些又不是设备,又不能让 ...

随机推荐

  1. Golang面向并发的内存模型

    Import Advanced Go Programming 1.5 面向并发的内存模型 在早期,CPU都是以单核的形式顺序执行机器指令.Go语言的祖先C语言正是这种顺序编程语言的代表.顺序编程语言中 ...

  2. 【Linux命令】系统状态检测命令8个(ifconfig、uname、uptime、free、who、last、history、sosreport)

    目录 ifconfig获取网卡配置信息 uname查看系统内核版本 uptime查看系统的负载信息 free查看内存信息 who查看当前主机用户的终端信息 last查看系统的登录记录 history查 ...

  3. 01-Git单人本地仓库操作

    Git源代码管理 Git(多人协同开发同一个项目),作用就是源代码管理,为什么需要源代码管理呢,方便多人协同开发,并且方便版本控制. Git管理源代码特点: 1.Git是分布式管理.服务器和客户端都有 ...

  4. bootstrap 输入框后面有个按钮

    效果如下:  实现代码:

  5. 从零开始学 ASP.NET Core 与 EntityFramework Core 目录

    从零开始学 ASP.NET Core 与 EntityFramework Core 介绍 我是一个目录,它旨在帮助开发者循序渐进的了解 ASP.NET Core 和 Entity Framework ...

  6. 转 SSD论文解读

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/u010167269/article/det ...

  7. Python【day 14-5】sorted filter map函数应用和练习

    '''''' ''' 内置函数或者和匿名函数结合输出 4,用map来处理字符串列表,把列表中所有人都变成sb,比方alex_sb name=[‘oldboy’,'alex','wusir'] 5,用m ...

  8. cmdb全总结

    1.什么是cmdb ,做什么的? 配置管理数据库 ,就是存储基础设施的信息配置使用的 简单说就是CMDB这个系统可以自动发现网络上的IT设备 ,并自动存储相关信息 ,像一台服务器有型号 厂商 系统 c ...

  9. PHP setcookie 网络函数

    setcookie - 发送 Cookie. 语法: setcookie ( string $name [, string $value = "" [, int $expire = ...

  10. Dynamics 365 Customer Engagement中使用JavaScript和C#调用操作Action示例

    微软动态CRM专家罗勇 ,回复334或者20190509可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me! Action (操作)是流程的一种,可以在工作流中调用,可以使用 ...