El camino de crecimiento de la arquitectura de Internet de las cosas: utilizando Netty para analizar los dispositivos de transmisión de usuarios de Internet de las cosas

I. Introducción

  La mayoría de los blogs anteriores introdujeron middleware basado en EMQ, el protocolo de comunicación usa MQTT y los datos transmitidos son datos de texto sin formato en formato JSON. De esta manera, a la mayoría de las personas que están familiarizadas con el desarrollo web y el desarrollo de software les gusta usarlo a primera vista. Dado que también estoy desarrollando software web, prefiero este enfoque. La plataforma IoT de Ali también recomienda este enfoque. Sin embargo, si está acostumbrado al desarrollo de hardware, el desarrollo integrado prefiere utilizar una conexión TCP-Socket desnuda. Se utiliza el protocolo binario. En base a esto, en la mayoría de las aplicaciones, para ser compatible con dispositivos antiguos, es necesario desarrollar una puerta de enlace de servidor TCP separada. Aquí está el marco de trabajo de Netty más popular que he aprendido antes.

  No hay mucho que decir, empecemos.

 

 2. Acuerdo

definición

descripción

Carácter de inicio '@@'

(2 bytes)

El primer y segundo bytes del paquete de datos son valores fijos de 64 y 64.

unidad de control

 

Número de serie comercial

(2 bytes)

El tercer y cuarto bytes del paquete de datos. En el modo de envío / confirmación, el remitente incrementa el número de serie del servicio en uno en orden al enviar un nuevo paquete de datos, y el confirmador regresa de acuerdo con el número de serie del servicio del paquete enviado; en el modo de solicitud / respuesta, el solicitante envía el número de serie del servicio en el nuevo paquete de datos. Cuando el comando de solicitud se agrega en uno en orden, el respondedor regresa de acuerdo con el número de serie comercial del paquete de solicitud. El byte bajo se transmite primero. El número de serie del servicio es un entero positivo de 2 bytes, que se determina cuando las partes de la comunicación establecen una conexión de red por primera vez. El valor inicial es 0. El iniciador del servicio gestiona de forma independiente el número de serie del servicio (el iniciador del servicio se refiere al remitente en el modo de envío / confirmación o al solicitante en el modo de solicitud / respuesta). El iniciador comercial es responsable de la asignación y recuperación del número de serie comercial para garantizar la unicidad del número de serie comercial durante la duración del negocio.

Número de versión del protocolo

(2 bytes)

El número de versión del protocolo incluye el número de versión principal (el quinto byte) y el número de versión del usuario (el sexto byte). El número de versión principal es un valor fijo de 1 y el número de versión de usuario lo define el usuario.

Sello de tiempo

(6 bytes)

Los bytes 7 a 12 del paquete de datos son el momento en que se envía el paquete de datos, como se define en la Tabla 2.

Dirección de la fuente

(6 bytes)

Los bytes 13 al 18 del paquete de datos son la dirección de origen del paquete de datos (la dirección del centro de monitoreo o del dispositivo de transmisión de información del usuario). El byte bajo se transmite primero.

Dirección de destino

(6 bytes)

Los bytes 19 al 24 del paquete de datos son la dirección de destino del paquete de datos (la dirección del centro de monitoreo o del dispositivo de transmisión de información del usuario). El byte bajo se transmite primero.

Longitud de la unidad de datos de aplicación

(2 bytes)

Los bytes 25 y 26 del paquete de datos son la longitud de la unidad de datos de la aplicación, y la longitud no debe ser superior a 1024; el byte bajo se transmite primero.

Byte de comando

(1 byte)

El byte 27 del paquete de datos es el byte de comando de la unidad de control Consulte la Tabla 3 para obtener definiciones específicas.

Unidad de datos de aplicación

(Máximo 1024 bytes)

El formato básico de la unidad de datos de la aplicación se muestra en la Tabla 3. Para paquetes de comando como confirmación / rechazo, esta unidad puede estar vacía.

Suma de comprobación

(1 byte)

La suma de verificación aritmética de cada byte de datos en la unidad de control (del 3º al 27º byte) y la unidad de datos de la aplicación es un número binario de 1 byte formado descartando más de 8 bits de acarreo.

Carácter final '##'

(2 bytes)

El valor fijo es 35,35.

  Lo anterior es el formato de datos binarios que debe procesarse esta vez.

 

Tres, la parte del código

  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

Supongo que te gusta

Origin blog.csdn.net/u010460625/article/details/108381842
Recomendado
Clasificación