0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

鴻蒙OS開(kāi)發(fā)實(shí)戰(zhàn):【Socket小試MQTT連接】

jf_46214456 ? 2024-04-01 16:14 ? 次閱讀

本篇分享一下 HarmonyOS 中的Socket使用方法

將從2個(gè)方面實(shí)踐:

  1. HarmonyOS 手機(jī)應(yīng)用連接PC端 SocketServer
  2. HarmonyOS 手機(jī)應(yīng)用連接MQTT 服務(wù)端

通過(guò)循序漸進(jìn)的方式,全面了解實(shí)踐HarmonyOS中的Socket用法

學(xué)習(xí)本章前先熟悉文檔開(kāi)發(fā)知識(shí)更新庫(kù)gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md前往。

V2.0白皮書(shū).png

注意 :編譯時(shí)IDE會(huì)給出如下警告提示,@ohos.net.socket 這個(gè)包沒(méi)有驗(yàn)證過(guò)。

或者+mau123789熟悉文檔是v喔!

Currently module for '@ohos.net.socket' is not verified. If you're importing napi, its verification will be enabled in later SDK version. Please make sure the corresponding .d.ts file is provided and the napis are correctly declared.

官方文檔說(shuō)明

引入Socket包

import socket from '@ohos.net.socket';

創(chuàng)建TCPSocket,連接遠(yuǎn)端服務(wù)器

//注意,這里聲明變量tcp, 建議將類型加上,否則不利于IDE聯(lián)想API
let tcp: socket.TCPSocket = socket.constructTCPSocketInstance();

let bindAddress = {
  address: '192.168.xx.xx',
  port: x
};

let connectAddress = {
  address: '192.168.xx.xx',
  port: x
};

//1. 綁定本機(jī)地址和端口
tcp.bind(bindAddress, err = > {

  if(err){
    console.log('1-' + JSON.stringify(err))
    return
  }

  //2. 連接遠(yuǎn)端服務(wù)器
  tcp.connect({
    address: connectAddress,
    timeout: 30000
  }).then( r = > {
    console.log('2-' +JSON.stringify(r))
  }).catch((e) = > {
    console.log('3-' + JSON.stringify(e))
  })

})
復(fù)制

狀態(tài)監(jiān)聽(tīng)

訂閱“連接”

tcp.on('connect', () = > {
    
});
復(fù)制

解除“連接”訂閱

tcp.off('connect', () = > {
    
});
復(fù)制

訂閱“消息”

tcp.on('message', () = > {
    //即:可以在這里隨時(shí)接收到服務(wù)端發(fā)送過(guò)來(lái)的消息
});
復(fù)制

解除“消息”訂閱

tcp.off('message', () = > {
   
});
復(fù)制

發(fā)送消息

let msg: string = '我是HarmonyOS客戶端'

tcp.send({data: msg}, (error)= >{
  if(error) {
    console.log('消息沒(méi)有發(fā)送成功: ' + JSON.stringify(error))
  } else {
    console.log('消息發(fā)送成功')
  }
})
復(fù)制

實(shí)踐:實(shí)現(xiàn)Socket與ServerSocket通信

創(chuàng)建ServerSocket 服務(wù)

這里使用IntelliJ IDEA創(chuàng)建一個(gè)Java工程,然后運(yùn)行在自己電腦上即可使用

如果你實(shí)在沒(méi)法自己實(shí)現(xiàn)ServerSocket,可以在網(wǎng)上找一個(gè)調(diào)試Socket的工具

監(jiān)聽(tīng)客戶端接入

package com.harvey.socketserver;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Main {

    public static void main(String[] args) {
            try {
                ServerSocket serverSocket = new ServerSocket(6666);

                //一. 建立客戶端監(jiān)聽(tīng)
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        while (true){
                            try {
                                Socket clientSocket = serverSocket.accept();

                                System.out.println("客戶端:" + clientSocket.getInetAddress().getLocalHost()+"已連接到服務(wù)器");

                                new Server(clientSocket).start();

                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }).start();

            } catch (IOException e) {
                e.printStackTrace();
            }
    }

}
復(fù)制

監(jiān)聽(tīng)客戶端消息且自動(dòng)回復(fù)

package com.harvey.socketserver;

import java.io.*;
import java.net.Socket;

public class Server extends Thread{

    Socket clientSocket;
    InputStream is;
    OutputStream os;
    String lastReceiverMessage;

    int LIVE_TIME = 60*1000;

    public Server(Socket clientSocket){
        this.clientSocket = clientSocket;
        try {
            is = this.clientSocket.getInputStream();
            os = this.clientSocket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {

        while(LIVE_TIME != 0){

            if ( this.clientSocket != null ) {

                if ( this.clientSocket.isClosed() || this.clientSocket.isInputShutdown() || this.clientSocket.isOutputShutdown()) {
                    LIVE_TIME = 0;
                } else {
                    readMessage();

                    responseMessage();

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    LIVE_TIME -= 1000;
                }

            } else {
                LIVE_TIME = 0;
            }

        }

        closeAllChannel();

    }

    //釋放資源
    private void closeAllChannel(){
        try {
            if(clientSocket != null){
                clientSocket.close();
                clientSocket = null;
            }
            if(is != null){
                is.close();
                is = null;
            }
            if(os != null){
                os.close();
                os = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //讀取客戶端消息, 注意:這里是為了省事,用的readLine接口
    //如果消息中有換行符,則會(huì)丟失消息
    private void readMessage(){

        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        try {
            lastReceiverMessage  = br.readLine();
            System.out.println("已接收到端消息:【" + lastReceiverMessage +"】");
        } catch (IOException e) {
            System.err.println("接收消息失敗:" + e.getMessage());
        }

    }

    //自動(dòng)回復(fù)客戶端消息
    private void responseMessage(){
        try {
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
            bw.write(System.currentTimeMillis() + "親愛(ài)的客戶端,已收到您的來(lái)信。"  +  lastReceiverMessage + "n");
            bw.flush();
            System.out.println("回復(fù)消息成功");
        } catch (IOException e) {
            System.err.println("回復(fù)消息失敗:" + e.getMessage());
        }

    }

}
復(fù)制

創(chuàng)建客戶端應(yīng)用

布局

為了驗(yàn)證Socket,交互頁(yè)面包含如下功能:

  1. 連接/斷開(kāi)
  2. 渲染接收到的消息
  3. 渲染已發(fā)送的消息
  4. 文字輸入
  5. 消息發(fā)送

HarmonyOS 核心代碼

import socket from '@ohos.net.socket'
import util from '@ohos.util';
import Prompt from '@system.prompt';

let tcpSocket: socket.TCPSocket = null

@Entry
@Component
struct SocketPage {

  @State isConnected: boolean = false
  
  @State sendMessage: string = ''
  @State inputMessage: string = ''
  @State receiveMessage: string = ''

  @State connectButtonBGColor: Color = Color.Gray
  @State connectButtonTextColor: Color = Color.White

  //頁(yè)面創(chuàng)建時(shí),注冊(cè)自定義消息,監(jiān)聽(tīng)來(lái)消息和連接狀態(tài)
  aboutToAppear(){

    getContext().eventHub.on('remotemsg', (value)= >{
        this.receiveMessage = value
    })

    getContext().eventHub.on('connectStatus', (value)= >{
        if(value === 'connect'){
          this.connectButtonBGColor = Color.Green
        } else if(value === 'close'){
          this.connectButtonBGColor = Color.Gray
        }
    })

  }

  //頁(yè)面銷毀時(shí),解除所有訂閱,關(guān)閉socket
  aboutToDisappear() {
     tcpSocket.off("message")
     tcpSocket.off("connect")
     tcpSocket.off("close")
     tcpSocket.close()
     tcpSocket = null
  }
  build(){

        Column( {space: 20} ){

          Row( {space: 20} ){
            Button('連接').width(60).height(60).fontSize(12)
              .backgroundColor(this.connectButtonBGColor)
              .fontColor(this.connectButtonTextColor)
              .onClick( ()= > {
                
                if(this.isConnected){
                  tcpSocket.close()
                } else {
                  connectServer()
                }
                
              })
          }

          Column({space: 30}){
            Text('發(fā)送:' + this.sendMessage).fontSize(20).width('100%')
            Text('接收:' + this.receiveMessage).fontSize(20).width('100%')
          }.backgroundColor(Color.Pink)
          .padding( { top: 20, bottom: 20} )

          Row({space: 10}) {
            TextArea({placeholder: '輸入文字', text: this.inputMessage})
              .onChange( (value) = > {
                this.inputMessage = value
              })
              .fontSize(20)
              .width('75%')

            Button('發(fā)送').fontColor(29).onClick( () = > {
              sendMessage(this.inputMessage)
              this.sendMessage = this.inputMessage
              this.inputMessage = ''
            }).width('20%')
          }
          .width('100%')
          .justifyContent(FlexAlign.Center)

        }
        .width('100%')
        .height('100%')
        .alignItems(HorizontalAlign.Start)
        .justifyContent(FlexAlign.Start)
        .padding({top: px2vp(120)})

  }
}


//發(fā)送消息
function sendMessage(msg: string){
  if(tcpSocket){
    tcpSocket.send({data: msg + 'n'}, (error)= >{
      if(error) {
        console.log('消息沒(méi)有發(fā)送成功: ' + JSON.stringify(error))
      } else {

        getContext().eventHub.emit('')
        console.log('消息發(fā)送成功')
      }
    })
  } else {
    Prompt.showToast({message: '還沒(méi)有連接服務(wù)器'})
  }
}

//開(kāi)始連接服務(wù)器
function connectServer(){

  let bindAddress = {
    address: '192.168.71.66',
    port: 1983,
    family: 1
  };

  let connectAddress = {
    address: '192.168.71.23',
    port: 6666 //端口號(hào)要和ServerSocket 一致
  };

  tcpSocket = socket.constructTCPSocketInstance()

  tcpSocket.on('close', () = > {
    console.log("on close")
    getContext().eventHub.emit('connectStatus', 'close')
  });

  tcpSocket.on('connect', () = > {
      console.log("on connect")
      getContext().eventHub.emit('connectStatus', 'connect')
  });

  tcpSocket.on('message' , ( value: {message: ArrayBuffer, remoteInfo: socket.SocketRemoteInfo} ) = > {

    let view = new Uint8Array(value.message);
    let textDecoder = util.TextDecoder.create()
    let str = textDecoder.decodeWithStream(view);

    getContext().eventHub.emit('remotemsg', str)
  })


  tcpSocket.bind(bindAddress, err = > {

    if(err){
      console.log('1-' + JSON.stringify(err))
      return
    }

    tcpSocket.connect({
      address: connectAddress,
      timeout: 30000
    }).then( r = > {
      console.log('2-' +JSON.stringify(r))
    }).catch((e) = > {
      console.log('3-' + JSON.stringify(e))
    })

  })

}
復(fù)制

最終效果

實(shí)踐:實(shí)現(xiàn)MQTT連接

準(zhǔn)備MQTT Broker

MQTT使用的是 mosquitto,官網(wǎng)下載地址

關(guān)于MQTT的入門(mén)使用,可參見(jiàn)“MQTT試用

注意:mosquitto 安裝完成后,需要打開(kāi)匿名設(shè)置,并且監(jiān)聽(tīng)自己電腦的IP和1883端口 mosquitto的配置文件名:mosquitto.conf

  • allow_anonymous true
  • listener 1883 192.168.xxx.xxx

MQTT 5.0 網(wǎng)址

https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.pdf

  1. 熟悉 “3.1 CONNECT – Connection Request”
  2. 熟悉 “3.2 CONNACK – Connect acknowledgement”

場(chǎng)景模擬

客戶端使用Socket 連接mosquitto, 并且響應(yīng)連接ACK

代碼實(shí)現(xiàn)

請(qǐng)求連接

這部分需要分為兩步:1. Socket連接 2. MQTT連接請(qǐng)求(即發(fā)送連接請(qǐng)求命令)

a. Socket連接

function connectMQTTServer(){

  let bindAddress = {
    address: '192.168.71.66',
    port: 1983,
    family: 1
  };

  let connectAddress = {
    address: '192.168.71.23', //MQTT服務(wù)器IP
    port: 1883 //MQTT服務(wù)器端口
  };

  tcpSocket = socket.constructTCPSocketInstance()

  listenerStatus()

  tcpSocket.bind(bindAddress, err = > {

    if(err){
      console.log('1-' + JSON.stringify(err))
      return
    }

    tcpSocket.connect({
      address: connectAddress,
      timeout: 30000
    }).then( r = > {
      console.log('2-' +JSON.stringify(r))
    }).catch((e) = > {
      console.log('3-' + JSON.stringify(e))
    })

  })
}
復(fù)制

b. MQTT連接請(qǐng)求

tcpSocket.on('connect', () = > {
  console.log("on connect")

   //拼接MQTT請(qǐng)求數(shù)據(jù)
  let connectCMD = MQTTConnect.getFixHeader()

  //發(fā)送MQTT連接請(qǐng)求命令
  tcpSocket.send({data: connectCMD.buffer}, (error)= >{
    if(error) {
      console.log('消息沒(méi)有發(fā)送成功: ' + JSON.stringify(error))
    } else {
      console.log('消息發(fā)送成功')
    }
  })

  getContext().eventHub.emit('connectStatus', 'connect')
});
復(fù)制

構(gòu)建MQTT請(qǐng)求連接數(shù)據(jù)

代碼有點(diǎn)枯燥,都是要對(duì)著MQTT 5.0規(guī)范文檔來(lái)實(shí)現(xiàn)的

import util from '@ohos.util'

export default class MQTTConnect{

  //3.1.1 CONNECT Fixed Header 【2字節(jié)】
  //3.1.2 CONNECT Variable Header
      //3.1.2.1 Protocol Name 【6字節(jié)】
      //3.1.2.2 Protocol Version 【1字節(jié)】
      //3.1.2.3 Connect Flags 【1字節(jié)】
      //3.1.2.10 Keep Alive 【2字節(jié)】
      //3.1.2.11 CONNECT Properties
          //3.1.2.11.1 Property Length 【1字節(jié)】
          //3.1.2.11.2 Session Expiry Interval 【4字節(jié)】
          //3.1.2.11.3 Receive Maximum 【2字節(jié)】
          //3.1.2.11.4 Maximum Packet Size 【4字節(jié)】
          //3.1.2.11.5 Topic Alias Maximum 【2字節(jié)】
          //3.1.2.11.6 Request Response Information 【1字節(jié)】
          //3.1.2.11.7 Request Problem Information 【1字節(jié)】
          //3.1.2.11.8 User Property【UTF-8 String Pair】
          //3.1.2.11.9 Authentication Method 【UTF-8 String】
          //3.1.2.11.10 Authentication Data【Binary Data】
  //3.1.3 CONNECT Payload
      //3.1.3.1 Client Identifier (ClientID) 【UTF-8 String】
      //3.1.3.2 Will Properties
          //3.1.3.2.1 Property Length 【Variable Byte Integer】
          //3.1.3.2.2 Will Delay Interval 【4字節(jié)】
          //3.1.3.2.3 Payload Format Indicator 【1字節(jié)】
          //3.1.3.2.4 Message Expiry Interval 【4字節(jié)】
          //3.1.3.2.5 Content Type【UTF-8 String】
          //3.1.3.2.6 Response Topic【UTF-8 String】
          //3.1.3.2.7 Correlation Data 【Binary Data】
          //3.1.3.2.8 User Property【UTF-8 String Pair】
     //3.1.3.3 Will Topic 【UTF-8 String】
     //3.1.3.4 Will Payload【 Binary Data】
     //3.1.3.5 User Name【UTF-8 String】
     //3.1.3.6 Password【 Binary Data】
  //3.1.4 CONNECT Actions


   public static getFixHeader(): Uint8Array{
      let remainLength: number = 0

      //3.1.1 CONNECT Fixed Header - 包類型
       let abPacketType = new ArrayBuffer(1)
       const dv_abPacketType = new DataView(abPacketType);
       dv_abPacketType.setInt8(0, 0x10)

      //3.1.2.1 Protocol Name

      let u8a_protolName = this.utf8String('MQTT')
      remainLength += u8a_protolName.length

      //3.1.2.2 Protocol Version
      let version = new Uint8Array([5])
      remainLength++

      //3.1.2.3 Connect Flags
      const  UserNameFlag: number = 0x80
      const  PasswordFlag: number = 0x40
      const  WillRetain: number = 0x20
      const  WillQoS0: number = 0x00
      const  WillQoS1: number = 0x8
      const  WillQoS2: number = 0x10
      const  WillQoS3: number = 0x18
      const  WillFlag: number = 0x4
      const  CleanStart: number = 0x2

      let connectFlags: number = 0
      //可以根據(jù)實(shí)際對(duì)外暴露的接口,在這里進(jìn)行與運(yùn)算
      connectFlags = CleanStart
      let u8a_connectFlags = new Uint8Array([connectFlags])
      remainLength++

      //3.1.2.10 Keep Alive
      const keepAlive = 60

      let u8a_keepalive = new Uint8Array([(keepAlive & 0xff00) > > 8 , keepAlive & 0xff])
      remainLength += 2

      //3.1.2.11 CONNECT Properties
      //3.1.2.11.1 Property Length
      let u8a_propertylength = new Uint8Array([0])
      remainLength++

      //3.1.3 CONNECT Payload
      //3.1.3.1 Client Identifier (ClientID)
      let u8a_clientidentifier = this.utf8String('Harvey鴻蒙')
      remainLength += u8a_clientidentifier.length

      //3.1.1 CONNECT Fixed Header - 包剩余長(zhǎng)度
      let abRemainLength = new ArrayBuffer(1)
      const dv_remainLength = new DataView(abRemainLength);
      dv_remainLength.setInt8(0, remainLength)

      let allIndex: number = 0
      let allUint8Array = new Uint8Array(2 + remainLength)
      allUint8Array[allIndex++] = dv_abPacketType.getUint8(0) //包類型
      allUint8Array[allIndex++] = dv_remainLength.getUint8(0) //包剩余長(zhǎng)度
      u8a_protolName.forEach((value)= >{                       //協(xié)議名稱
         allUint8Array[allIndex++] = value
      })
      version.forEach((value)= >{                              //協(xié)議版本號(hào)
         allUint8Array[allIndex++] = value
      })
      u8a_connectFlags.forEach((value)= >{                     //連接標(biāo)志
         allUint8Array[allIndex++] = value
      })
      u8a_keepalive.forEach((value)= >{                        //長(zhǎng)連保活時(shí)間
         allUint8Array[allIndex++] = value
      })
      u8a_propertylength.forEach((value)= >{                   //連接屬性長(zhǎng)度
         allUint8Array[allIndex++] = value
      })
      u8a_clientidentifier.forEach((value)= >{                 //客戶端名稱
         allUint8Array[allIndex++] = value
      })

      //數(shù)值打印
      let str = [...new Uint8Array(abPacketType),...new Uint8Array(abRemainLength), ...u8a_protolName, ...version
          , ...u8a_connectFlags, ...u8a_keepalive, ...u8a_propertylength, ...u8a_clientidentifier]
         .map(x = > x.toString(16).padStart(2, '0'))
         .join(' ')

      console.log(str)

      let allStr: string = ''

      allUint8Array.forEach((value) = > {
         allStr = allStr.concat(value.toString(16).padStart(2, '0')).concat(' ')
      })
      console.log(allStr)

      return allUint8Array

   }

   private static utf8String(content: string): Uint8Array{
      const encoder = new util.TextEncoder()
      let u8a_encoder = encoder.encodeInto(content)

      let encoderLength = u8a_encoder.length

      let abEncoder = new ArrayBuffer(encoderLength + 2)
      const dv_encoder = new DataView(abEncoder)
      dv_encoder.setInt8(0, (encoderLength & 0xff00) > > 8)
      dv_encoder.setInt8(1, encoderLength & 0x00ff)

      let index: number = 2
      u8a_encoder.forEach( (value) = > {
         dv_encoder.setInt8(index++, value)
      })

      return new Uint8Array(abEncoder)
   }

}
復(fù)制

解析MQTT請(qǐng)求連接ACK數(shù)據(jù)

DevEco IDE 日志控制臺(tái)

tcpSocket.on('message' , ( value: {message: ArrayBuffer, remoteInfo: socket.SocketRemoteInfo} ) = > {

  let str = [...new Uint8Array(value.message)]
    .map(x = > x.toString(16).padStart(2, '0'))
    .join(' ')

  console.log(str)

  let index: number = 0

  let uint8Array = new Uint8Array(value.message)

  let cfh = uint8Array[index]

  index++

  //3.2.1 CONNACK Fixed Header
  //解析MQTT ACK數(shù)據(jù),轉(zhuǎn)換為日志輸出
  if(cfh == 32){
    console.log('Fixed Header format:CONNACK('+cfh+')')
    MQTTConnectACK.parse(index, uint8Array)
  }

  getContext().eventHub.emit('remotemsg', str)
})
復(fù)制
import MQTTTool from './MQTTTool'

export default class MQTTConnectACK{

  public static parse(index: number, uint8Array: Uint8Array) {
      let remainLength = uint8Array[index]
      console.log('Remaining Length:' + remainLength.toString(16))
      index++

      if(remainLength == 0){
        return
      }

      let remainIndex: number = 0

      //3.2.2 CONNACK Variable Header
      //3.2.2.1 Connect Acknowledge Flags
      let caf = uint8Array[index]
      console.log('Connect Acknowledge Flags:' + caf.toString(16))
      index++
      remainIndex++

      if(remainIndex >= remainLength){
        return
      }

      //3.2.2.2 Connect Reason Code
      let crc = uint8Array[index]
      let des: string = ''
      if(crc == 0){
         des = 'Success'
      } else if(crc == 128){
         des = 'Unspecified error'
      } else if(crc == 129){
         des = 'Malformed Packet'
      } else if(crc == 130){
        des = 'Protocol Error'
      } else if(crc == 131){
        des = 'Implementation specific error'
      } else if(crc == 132){
        des = 'Unsupported Protocol Version'
      } else if(crc == 133){
        des = 'Client Identifier not valid'
      } else if(crc == 134){
        des = 'Bad User Name or Password'
      } else if(crc == 135){
        des = 'Not authorized'
      } else if(crc == 136){
        des = 'Server unavailable'
      } else if(crc == 137){
        des = 'Server busy'
      } else if(crc == 138){
        des = 'Banned'
      } else if(crc == 140){
        des = 'Bad authentication method'
      } else if(crc == 144){
        des = 'Topic Name invalid'
      } else if(crc == 149){
        des = 'Packet too large'
      } else if(crc == 151){
        des = 'Quota exceeded'
      } else if(crc == 153){
        des = 'Payload format invalid'
      } else if(crc == 154){
        des = 'Retain not supported'
      } else if(crc == 155){
        des = 'QoS not supported'
      } else if(crc == 156){
        des = 'Use another server'
      } else if(crc == 157){
        des = 'Server moved'
      } else if(crc == 158){
        des = 'Connection rate exceeded'
      }
      console.log('Connect Reason Code:' + des)

      index++
      remainIndex++

      if(remainIndex >= remainLength){
        return
      }

      //3.2.2.3 CONNACK Properties
      //3.2.2.3.1 Property Length
      let propertyLength = uint8Array[index]
      console.log('Property Length:' + propertyLength.toString(16))

      index++
      remainIndex++

      if(propertyLength != 0){

        while (true){
          //判斷類型
          let nextType = uint8Array[index]

          index++
          remainIndex++
          if(remainIndex >= remainLength){
            return
          }

          if(nextType == 17){ //值為4個(gè)字節(jié)
            //3.2.2.3.2 Session Expiry Interval
            let costByteNumber = MQTTTool.parseFourByte(uint8Array, index, "Session Expiry Interval:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 33){//值為2個(gè)字節(jié)

            //3.2.2.3.3 Receive Maximum
            let costByteNumber = MQTTTool.parseTwoByte(uint8Array, index, "Receive Maximum:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 36){ //值為1個(gè)字節(jié)

            //3.2.2.3.4 Maximum QoS
            let mq = uint8Array[index]
            console.log('Maximum QoS:' + mq.toString(16))

            index++
            remainIndex++

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 37) {  //值為1個(gè)字節(jié)
            //3.2.2.3.5 Retain Available
            let ra = uint8Array[index]
            console.log('Retain Available:' + ra.toString(16))

            index++
            remainIndex++

            if(remainIndex >= remainLength){
              return
            }
          } else if(nextType == 39) { //值為4個(gè)字節(jié)

            //3.2.2.3.6 Maximum Packet Size
            let costByteNumber = MQTTTool.parseFourByte(uint8Array, index, "Maximum Packet Size:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 18) { //UTF-8 String = 2個(gè)字節(jié) + 2個(gè)字節(jié)值的字節(jié)

            //3.2.2.3.7 Assigned Client Identifier
            let costByteNumber = MQTTTool.parseUTF8String(uint8Array, index, "Assigned Client Identifier:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 34) { // 值為2個(gè)字節(jié)
            //3.2.2.3.8 Topic Alias Maximum
            let costByteNumber = MQTTTool.parseTwoByte(uint8Array, index, "Topic Alias Maximum:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 31) { //UTF-8 String = 2個(gè)字節(jié) + 2個(gè)字節(jié)值的字節(jié)
            //3.2.2.3.9 Reason String
            let costByteNumber = MQTTTool.parseUTF8String(uint8Array, index, "Reason String:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 38) {//UTF-8 String Pair = (2個(gè)字節(jié) + 2個(gè)字節(jié)值的字節(jié))+(2個(gè)字節(jié) + 2個(gè)字節(jié)值的字節(jié))
            //3.2.2.3.10 User Property
            let costByteNumber = MQTTTool.parseUTF8String(uint8Array, index, "User Property:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 40) { //值為1個(gè)字節(jié)
            //3.2.2.3.11 Wildcard Subscription Available
            let wsa = uint8Array[index]
            console.log('Wildcard Subscription Available:' + wsa.toString(16))

            index++
            remainIndex++

            if(remainIndex >= remainLength){
              return
            }
          } else if(nextType == 41) { //值為1個(gè)字節(jié)
            //3.2.2.3.12 Subscription Identifiers Available
            let sia = uint8Array[index]
            console.log('Subscription Identifiers Available:' + sia.toString(16))

            index++
            remainIndex++

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 42) { //值為1個(gè)字節(jié)
            //3.2.2.3.13 Shared Subscription Available
            let ssa = uint8Array[index]
            console.log('Shared Subscription Available:' + ssa.toString(16))

            index++
            remainIndex++

            if(remainIndex >= remainLength){
              return
            }
          } else if(nextType == 19) { //值為2個(gè)字節(jié)
            //3.2.2.3.14 Server Keep Alive
            let costByteNumber = MQTTTool.parseTwoByte(uint8Array, index, "Server Keep Alive:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 26) { //UTF-8 String = 2個(gè)字節(jié) + 2個(gè)字節(jié)值的字節(jié)
            //3.2.2.3.15 Response Information
            let costByteNumber = MQTTTool.parseUTF8String(uint8Array, index, "Response Information:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 28) { //UTF-8 String = 2個(gè)字節(jié) + 2個(gè)字節(jié)值的字節(jié)
            //3.2.2.3.16 Server Reference
            let costByteNumber = MQTTTool.parseUTF8String(uint8Array, index, "Server Reference:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 21) { //UTF-8 String = 2個(gè)字節(jié) + 2個(gè)字節(jié)值的字節(jié)
            //3.2.2.3.17 Authentication Method
            let costByteNumber = MQTTTool.parseUTF8String(uint8Array, index, "Authentication Method:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          } else if(nextType == 22) { //Binary Data = 2個(gè)字節(jié) + 2個(gè)字節(jié)值的字節(jié)
            //3.2.2.3.18 Authentication Data
            let costByteNumber = MQTTTool.parseBinaryData(uint8Array, index, "Authentication Data:")
            index += costByteNumber
            remainIndex += costByteNumber

            if(remainIndex >= remainLength){
              return
            }

          }
        }

    }
  }

}
復(fù)制

最終效果

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • MQTT
    +關(guān)注

    關(guān)注

    5

    文章

    640

    瀏覽量

    22360
  • 鴻蒙
    +關(guān)注

    關(guān)注

    57

    文章

    2294

    瀏覽量

    42633
  • HarmonyOS
    +關(guān)注

    關(guān)注

    79

    文章

    1957

    瀏覽量

    29908
  • OpenHarmony
    +關(guān)注

    關(guān)注

    25

    文章

    3611

    瀏覽量

    15968
  • 鴻蒙OS
    +關(guān)注

    關(guān)注

    0

    文章

    188

    瀏覽量

    4346
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    鴻蒙原生應(yīng)用開(kāi)發(fā)-網(wǎng)絡(luò)管理Socket連接(一)

    主要由socket模塊提供。具體接口說(shuō)明如下表。 TLS Socket連接主要由tls_socket模塊提供。具體接口說(shuō)明如下表。 本文參考引用HarmonyOS官方
    發(fā)表于 04-01 14:20

    鴻蒙OS崛起,鴻蒙應(yīng)用開(kāi)發(fā)工程師成市場(chǎng)新寵

    應(yīng)用的形態(tài)也在發(fā)生著翻天覆地的變化。作為全球領(lǐng)先的移動(dòng)操作系統(tǒng)和智能終端制造商,華為公司自主研發(fā)的鴻蒙OS應(yīng)運(yùn)而生,致力于構(gòu)建一個(gè)統(tǒng)一的分布式操作系統(tǒng),為各行各業(yè)的應(yīng)用開(kāi)發(fā)帶來(lái)全新的可能性。 一、
    發(fā)表于 04-29 17:32

    鴻蒙OS應(yīng)用程序開(kāi)發(fā)

    這份學(xué)習(xí)文檔主要是帶領(lǐng)大家在鴻蒙OS上學(xué)習(xí)開(kāi)發(fā)一個(gè)應(yīng)用程序,主要知識(shí)點(diǎn)如下:1、U-Boot引導(dǎo)文件燒寫(xiě)方式;2、內(nèi)核鏡像燒寫(xiě)方式;3、鏡像運(yùn)行。
    發(fā)表于 09-11 14:39

    Harmony OS物聯(lián)網(wǎng)應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn)(基于HiSpark WiFi IoT套件)第三講 課程資料

    本帖最后由 xusiwei1236 于 2020-11-20 14:24 編輯 Harmony OS物聯(lián)網(wǎng)應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn)(基于HiSpark WiFi IoT套件)第三講 課程資料全套課程資料
    發(fā)表于 09-29 10:47

    【HarmonyOS HiSpark Wi-Fi IoT HarmonyOS 智能家居套件試用 】基于鴻蒙OS系統(tǒng)的邊緣計(jì)算

    智能家居套件的基本組件和使用方法。2.使用提供的基本源代碼完成在開(kāi)發(fā)板上的鴻蒙OS系統(tǒng)的搭建和使用,嘗試搭建低功耗的鴻蒙OS系統(tǒng)進(jìn)行采集數(shù)
    發(fā)表于 10-29 14:06

    Harmony OS物聯(lián)網(wǎng)應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn)(基于HiSpark WiFi IoT套件)第三講 課程資料

    本帖最后由 xusiwei1236 于 2020-11-20 14:23 編輯 Harmony OS物聯(lián)網(wǎng)應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn)(基于HiSpark WiFi IoT套件)第三講 課程資料全套課程資料
    發(fā)表于 11-20 14:21

    【直播預(yù)熱】Harmony MQTT/CoAP應(yīng)用指南——火熱報(bào)名中

    (Hi3861V100) HarmonyOS物聯(lián)網(wǎng)應(yīng)用開(kāi)發(fā)實(shí)戰(zhàn)分享系列課程的第五課,也是此系列課程的最后一課,將為各位開(kāi)發(fā)者詳細(xì)講解鴻蒙MQTT
    發(fā)表于 12-09 17:18

    鴻蒙北向應(yīng)用,如何開(kāi)發(fā)mqtt功能

    一直都是做linux,C開(kāi)發(fā)、QT開(kāi)發(fā)的,沒(méi)android的app開(kāi)發(fā)經(jīng)驗(yàn)。提的問(wèn)題可能比較外行。鴻蒙北向,看了些書(shū),java跟js開(kāi)發(fā)都初
    發(fā)表于 09-07 11:24

    MQTTSocket的區(qū)別在哪

    MQTTSocket 區(qū)別:通俗來(lái)講:mqtt是對(duì)socket進(jìn)一步封裝。穩(wěn)定性更好,消耗流量更小,連接更加安全, 大公司物聯(lián)網(wǎng)目前主
    發(fā)表于 02-23 07:10

    鴻蒙 OS 應(yīng)用開(kāi)發(fā)初體驗(yàn)

    的操作系統(tǒng)平臺(tái)和開(kāi)發(fā)框架。HarmonyOS 的目標(biāo)是實(shí)現(xiàn)跨設(shè)備的無(wú)縫協(xié)同和高性能。 DevEco Studio 對(duì)標(biāo) Android Studio,開(kāi)發(fā)鴻蒙 OS 應(yīng)用的 IDE。
    發(fā)表于 11-02 19:38

    鴻蒙OS 2.0手機(jī)開(kāi)發(fā)者Beta版發(fā)布會(huì)在京舉辦

    三個(gè)月前,鴻蒙OS 2.0正式在華為開(kāi)發(fā)者大會(huì)2020亮相。12月16日,鴻蒙OS 2.0手機(jī)開(kāi)發(fā)
    的頭像 發(fā)表于 12-16 09:29 ?1.9w次閱讀

    鴻蒙os怎么升級(jí)

    6月2日,華為正式發(fā)布了鴻蒙armonyOS 2系統(tǒng),那么鴻蒙os如何升級(jí)?現(xiàn)將鴻蒙os升級(jí)方式告知如下。
    的頭像 發(fā)表于 06-08 16:26 ?2673次閱讀

    華為開(kāi)發(fā)者大會(huì)2021鴻蒙os在哪場(chǎng)

    華為開(kāi)發(fā)者大會(huì)2021將在10月22日-24日舉辦,地點(diǎn)為東莞松山湖,鴻蒙os 3.0或?qū)⑴c我們見(jiàn)面,那么華為開(kāi)發(fā)者大會(huì)2021鴻蒙
    的頭像 發(fā)表于 10-22 15:24 ?1834次閱讀

    RISC-V MCU開(kāi)發(fā)實(shí)戰(zhàn) (三):移植鴻蒙OS項(xiàng)目

    移植鴻蒙OS項(xiàng)目
    的頭像 發(fā)表于 11-01 11:08 ?2825次閱讀
    RISC-V MCU<b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b> (三):移植<b class='flag-5'>鴻蒙</b><b class='flag-5'>OS</b>項(xiàng)目

    鴻蒙開(kāi)發(fā)實(shí)戰(zhàn):【網(wǎng)絡(luò)管理-Socket連接

    Socket在網(wǎng)絡(luò)通信方面的應(yīng)用,展示了Socket在兩端設(shè)備的連接驗(yàn)證、聊天通信方面的應(yīng)用。
    的頭像 發(fā)表于 03-19 22:04 ?787次閱讀
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b>:【網(wǎng)絡(luò)管理-<b class='flag-5'>Socket</b><b class='flag-5'>連接</b>】