The growth path of the Internet of Things architecture-using Netty to analyze Internet of Things user transmission devices

I. Introduction

  Most of the previous blogs introduced middleware based on EMQ, the communication protocol uses MQTT, and the transmitted data is plain text data in JSON format. This way, most people who are familiar with Web development and software development like to use it at first glance. Since I am also doing web software development, I prefer this approach. Ali's IoT platform also recommends this approach. However, if you are used to hardware development, embedded development prefers to use bare TCP-Socket connection. The binary protocol is used. Based on this, in most applications, in order to be compatible with old devices, a separate TCP server gateway needs to be developed. Here is the more popular Netty framework that I have learned before.

  Not much to say, let’s start.

 

 2. Agreement

definition

description

Start character'@@'

(2 bytes)

The first and second bytes of the data packet are fixed values ​​of 64 and 64.

control unit

 

Business serial number

(2 bytes)

The 3rd and 4th bytes of the data packet. In the send/confirm mode, the service serial number is increased by one by the sender in order when sending a new data packet, and the confirmer returns according to the service serial number of the sent packet; in the request/response mode, the service serial number is sent by the requester when the new data packet is sent. When the request command is added by one in order, the responder returns according to the business serial number of the request packet. The low byte is transmitted first. The service serial number is a 2-byte positive integer, which is determined when the communication parties establish a network connection for the first time. The initial value is 0. The service serial number is independently managed by the service initiator (the service initiator refers to the sender in the send/confirm mode or the requester in the request/response mode). The business initiator is responsible for the allocation and recovery of the business serial number to ensure the uniqueness of the business serial number during the duration of the business.

Protocol version number

(2 bytes)

The protocol version number includes the main version number (the 5th byte) and the user version number (the 6th byte). The main version number is a fixed value of 1, and the user version number is defined by the user.

Time stamp

(6 bytes)

The 7th to 12th bytes of the data packet are the time when the data packet is sent out, as defined in Table 2.

source address

(6 bytes)

The 13th to 18th bytes of the data packet are the source address of the data packet (the address of the monitoring center or user information transmission device). The low byte is transmitted first.

Destination address

(6 bytes)

The 19th to 24th bytes of the data packet are the destination address of the data packet (the address of the monitoring center or user information transmission device). The low byte is transmitted first.

Application data unit length

(2 bytes)

The 25th and 26th bytes of the data packet are the length of the application data unit, and the length should not be greater than 1024; the low byte is transmitted first.

Command byte

(1 byte)

The 27th byte of the data packet is the command byte of the control unit. See Table 3 for specific definitions.

Application data unit

(Maximum 1024 bytes)

The basic format of the application data unit is shown in Table 3. For command packets such as confirmation/denial, this unit can be empty.

Checksum

(1 byte)

The arithmetic checksum of each byte data in the control unit (the 3rd to the 27th byte) and the application data unit is a 1-byte binary number formed by discarding more than 8 bits of carry.

End character'##'

(2 bytes)

The fixed value is 35,35.

  The above is the binary data format that needs to be processed this time.

 

Three, the code part

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

复制代码

 

  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     
19     private static final Logger log = LoggerFactory.getLogger(SmartIotHandler.class);
20 
21     @Override
22     protected void channelRead0(ChannelHandlerContext ctx, SmartIotProtocol iot)
23             throws Exception {
24         log.info("收到设备数据包: " + iot.getFlowid());
25         iot.printDebugInfo();
26         ctx.write("ok");
27     }
28     
29     @Override
30     public void channelActive(ChannelHandlerContext ctx) throws Exception {
31         InetSocketAddress socket = (InetSocketAddress) ctx.channel().remoteAddress();
32         String ip = socket.getAddress().getHostAddress();
33         log.info("收到客户端IP: " + ip);
34     }
35     
36     @Override
37     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
38         ctx.close();
39     }
40 }

复制代码

 

  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     
18     public static void main(String[] args) {
19         SpringApplication.run(IoTNettyPlatFormApplication.class, args);
20         run();
21     }
22 
23     private static NettyServer nettyServer = new NettyServer();
24     
25     private static void run(){
26         Thread thread = new Thread(new Runnable() {
27             @Override
28             public void run() {
29                 nettyServer.run();                
30             }
31         });
32         thread.start();
33     }
34     
35 }

复制代码

  我这里通过在@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

Guess you like

Origin blog.csdn.net/u010460625/article/details/108381842