Formulación e implementación de protocolo de aprendizaje a través de MQTT (2)

¡Comienza el viaje de crecimiento de los Nuggets! Este es el tercer día de mi participación en el "Desafío de actualización de diciembre del nuevo plan diario de Nuggets", haga clic para ver los detalles del evento

escrito en frente

Esta es la segunda parte del aprendizaje del protocolo MQTT La parte anterior introdujo el formato de mensaje del protocolo MQTT a través de la formulación e implementación del protocolo de aprendizaje MQTT (1) .

Cabecera fija Cabecera fija, todos los paquetes de control contienen
Cabecera variable Cabecera variable, algunos paquetes de control contienen
Carga útil Carga útil, parte del mensaje de control contiene

Este artículo simplemente implementa un servidor MQTT a través de Netty, usa el cliente MQTTX para enviar mensajes de control y usa Wiresharks para capturar paquetes para analizar diferentes tipos de mensajes de control, encabezados fijos, encabezados variables y partes de carga útil.

Implementación sencilla del servidor MQTT

Definición del servidor Netty MQTT

Defina un servidor Netty MQTT, que se implementa a través de ServerBootstrap. Acerca de Netty, creo que escribiré un artículo sistemáticamente más adelante. Para los estudiantes que no conocen a Netty, primero pueden considerar a Netty como una caja negra y simplemente entenderlo como un Servidor que vincula el puerto 60000.

MqttEncoder.INSTANCEAquí nos enfocamos en inicializar el canal, agregar , MqttDecoder, a la canalización del canal, mqttHandercodificar, decodificar y procesar la lógica comercial del flujo de bytes MQTT transmitido en el canal de red.

@Component
@RequiredArgsConstructor
public class MqttAgent {
    
    
?
    private final MqttHandler mqttHandler;
    private EventLoopGroup _bossGroup;
    private EventLoopGroup _workGroup;
?
    @PostConstruct
    public void start() throws Exception {
    
    
        try {
    
    
            _bossGroup = new NioEventLoopGroup(1);
            _workGroup = new NioEventLoopGroup();
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(_bossGroup, _workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
    
    
                        @Override
                        protected void initChannel(SocketChannel ch) {
    
    
                            ch.pipeline().addLast("mqttEncoder", MqttEncoder.INSTANCE);
                            ch.pipeline().addLast("mqttDecoder", new MqttDecoder());
                            ch.pipeline().addLast("mqttHandler", mqttHandler);
                        }
                    });
            serverBootstrap.bind(
                    "0.0.0.0",
                    60000
            ).sync();
        } catch (Exception e) {
    
    
            try {
    
    
                _bossGroup.shutdownGracefully();
                _workGroup.shutdownGracefully();
            } catch (Exception shutdownException) {
    
    
                // ignore
            }
            // rethrow exception while agent does not start up normally.
            throw e;
        }
    }
}

Implementación del controlador MQTT

MqttHandler maneja principalmente la lógica de procesamiento de los mensajes Mqtt, como verificar la contraseña de la cuenta de usuario y otros permisos cuando se establece la conexión. El procesamiento más simple aquí es imprimir el mensaje Mqtt y luego responder uno. El código es el siguiente MqttConnAckMessage:

@Component
@Slf4j
@ChannelHandler.Sharable
public class MqttHandler extends SimpleChannelInboundHandler<MqttMessage> {
    
    
    
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MqttMessage mqttMessage) throws Exception {
    
    
        //打印mqtt 消息
        log.info("mqtt message:{}", mqttMessage);
        //回复 connect ack 控制报文
        ctx.channel().writeAndFlush(connAckMessageInstance(MqttConnectReturnCode.CONNECTION_ACCEPTED));
    }
?
    //构造一个 MqttConnAckMessage
    public static MqttConnAckMessage connAckMessageInstance(MqttConnectReturnCode returnCode) {
    
    
        //连接确认标志+连接返回码(2位)
        MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.CONNACK, false,
                MqttQoS.AT_MOST_ONCE, false, 2);
        MqttConnAckVariableHeader variableHeader = new MqttConnAckVariableHeader(returnCode, false);
        return new MqttConnAckMessage(fixedHeader, variableHeader);
    }
}

El mensaje MqttConnAckMessage solo tiene encabezados fijos y variables, y no tiene carga útil.

  • Encabezado fijo: el valor del tipo de mensaje de control es 2, el bit de indicador es 0 y la longitud restante es un encabezado variable de dos bytes
  • Encabezado variable: 2 bytes, indicador de confirmación de conexión de un byte, el segundo byte es el código de retorno de la conexión

imagen-20221124222213855.png

programa de verificación

Utilice el cliente MQTTX para editar la información de conexión, host del servidor mqtt: 127.0.0.1, puerto: 60000 e inicie el servidor.

  • establecer conexiónimagen-20221124222558283.png

  • La conexión es exitosa, envía un mensajeimagen-20221124222929921.png

El servidor recibió correctamente el mensaje.

2022-11-24 22:39:49.304  INFO 8299 --- [ntLoopGroup-3-1] com.demo.mqttdemo.MqttHandler: mqtt message:MqttFixedHeader[messageType=PUBLISH, isDup=false, qosLevel=AT_MOST_ONCE, isRetain=false, remainingLength=22]
?

Captura de paquetes de Wiresharks

Abra el cliente de Wiresharks, MQTTX envía una solicitud de conexión y verifique los paquetes capturados de Wiresharks: como se muestra en la figura, No61, No62, No63 son el famoso protocolo de enlace de tres vías, No67, No69 son el mensaje de control MQTT Connect y el mensaje de control ConnAck .

imagen-20221124225713907.png

Conectar mensaje de control

imagen-20221124230044717.png

Se puede ver en la parte de DATOS del mensaje.

Dos bytes de encabezado fijo: 10 1a, 10 es el tipo de mensaje de control de conexión, 1a es la longitud restante

El encabezado variable del mensaje CONNECT: Contiene cuatro campos en el siguiente orden: Nombre de protocolo, Nivel de protocolo, Indicadores de conexión y Mantener vivo.

00 04 4d 51 54 54 Estos 6 bytes fijos indican el nombre del protocolo MQTT

ilustrar 7 6 5 4 3 2 1 0
nombre del protocolo
byte 1 Longitud MSB (0) 0 0 0 0 0 0 0 0
byte 2 LongitudLSB (4) 0 0 0 0 0 1 0 0
byte 3 'METRO' 0 1 0 0 1 1 0 1
byte 4 'Q' 0 1 0 1 0 0 0 1
byte 5 'T' 0 1 0 1 0 1 0 0
byte 6 'T' 0 1 0 1 0 1 0 0

Mensaje de control de ConnAck

imagen-20221124231203686.png

Encabezado fijo: 20 02 dos bytes indican el tipo de mensaje de control y la longitud restante, el formato del encabezado fijo de ConnAck es:

Poco 7 6 5 4 3 2 1 0
byte 1 0 0 1 0 0 0 0 0
byte 2 0 0 0 0 0 0 1 0

Encabezado variable: 00 00 dos bytes representan el indicador de confirmación de la conexión y el código de retorno de la conexión, el código de retorno de la conexión recibida es 0x00, por lo que los dos bytes son 00 00

Supongo que te gusta

Origin blog.csdn.net/qq_34626094/article/details/130516813
Recomendado
Clasificación