paho.mqtt.android代碼逐步分析(三)

MQTT與webSocket

Mqtt底層使用webSocket實現,經過發送http或https請求與服務端開始進行handshake,握手完成後協議將從http(https)升級成webSocket並創建長連,以後經過長連進行通訊。sdk中關於websocket部分結構及handshake信息以下:git

MQTT心跳包

分析心跳包首先看用於發送心跳信息的MqttPingReq.class和用於接收心跳答覆的MqttPingResp.classweb

而後,咱們須要從其發送的內容當中逆向推出其心跳包的內容。我 們先看其發送的的模塊:找到public class CommsSender implements Runnable 類,看到其有一個private MqttOutputStream out;私有字段,一看這個方法,咱們就能判斷,這個字段就是輸出流,打開public class MqttOutputStream extends OutputStream這個類,你會看到這樣一個方法:websocket

/**
    * Writes an <code>MqttWireMessage</code> to the stream.
    */
   public void write(MqttWireMessage message) throws IOException, MqttException {
      final String methodName = "write";
      byte[] bytes = message.getHeader();
      byte[] pl = message.getPayload();
//    out.write(message.getHeader());
//    out.write(message.getPayload());
      out.write(bytes,0,bytes.length);
      clientState.notifySentBytes(bytes.length);
      
        int offset = 0;
        int chunckSize = 1024;
        while (offset < pl.length) {
           int length = Math.min(chunckSize, pl.length - offset);
           out.write(pl, offset, length);
           offset += chunckSize;
           clientState.notifySentBytes(length);
        }     
      
      // @TRACE 500= sent {0}
       log.fine(CLASS_NAME, methodName, "500", new Object[]{message});
   }

原來,其發送的是header和payload,而後咱們再看看心跳包的header和payload。socket

MqttPingReq和MqttPingResp中都有這麼個方法:ide

protected byte[] getVariableHeader() throws MqttException {
   return new byte[0];
}

往上查看其共同父類MqttWireMessage.class中的getHeader():this

public byte[] getHeader() throws MqttException {
    try {
        int first = ((getType() & 0x0f) << 4) ^ (getMessageInfo() & 0x0f);
        byte[] varHeader = getVariableHeader();
        int remLen = varHeader.length + getPayload().length;//長度爲0

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        dos.writeByte(first);//寫入一個字節
        dos.write(encodeMBI(remLen));//查看encodeMBI()方法實現可知此處也是隻有一個字節
        dos.write(varHeader);//new byte[0]
        dos.flush();
        return baos.toByteArray();
    } catch(IOException ioe) {
        throw new MqttException(ioe);
    }
}
protected static byte[] encodeMBI( long number) {
   int numBytes = 0;
   long no = number;
   ByteArrayOutputStream bos = new ByteArrayOutputStream();
   // Encode the remaining length fields in the four bytes
   do {
      byte digit = (byte)(no % 128);
      no = no / 128;
      if (no > 0) {
         digit |= 0x80;
      }
      bos.write(digit);
      numBytes++;
   } while ( (no > 0) && (numBytes<4) );
   
   return bos.toByteArray();
}

而MqttWireMessage中還有一個getPayload方法,MqttPingReq和MqttPingResp都沒有重寫這個方法:spa

/**
 * Sub-classes should override this method to supply the payload bytes.
 */
public byte[] getPayload() throws MqttException {
   return new byte[0];
}

綜合以上分析可知MQTT的心跳包實際只有2個字節,且第一個字節中前4位表示消息類型後4位表示消息內容。code

相關文章
相關標籤/搜索