欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android開發(fā)MQTT協議的模型及通信淺析

 更新時間:2023年03月01日 10:37:28   作者:流浪漢kylin  
這篇文章主要W為大家介紹了Android開發(fā)MQTT協議的模型及通信淺析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

為什么要講MQTT協議?因為現在越來越多的領域會使用到這個協議,無論是做M2M,還是做Iot,或是想實現推送功能,MQTT都是一個不錯的選擇。

什么是MQTT協議

MQTT協議又稱為消息隊列要測傳輸協議,他是一種基于發(fā)布/訂閱范式的消息協議,并且它是一種基于TCP/IP協議族的應用層協議。

可以看出的它的特點:輕量、簡單、基于發(fā)布/訂閱范式、基于TCP/IP、是一種應用層協議。

如果還是不明白,我們可以簡單拿它和我們常用的http協議做個比較。

HTTP協議MQTT協議
基于TCP或UDP基于TCP
基于 請求/響應 模型基于 發(fā)布/訂閱 模型
http1.x是傳數據包傳輸二進制數據

MQTT協議的模型

我們得知道它是一個怎樣的模型才好去了解它的一個工作方式。比如說HTTP協議簡單分為兩個角色,一個Client代表客戶端,一個Server代表服務端。

而MQTT簡單來看分為3個角色,publisher表示發(fā)布者,subscriber表示訂閱者,它們兩個都是Client,所以任何一個Client客戶端既能充當publisher,也能充當subscriber。還有一個角色是broker表示代理,它是Server服務端。可以看出MQTT也是基于C/S的通信架構,只不過分為3種角色。

如果理解了這個模型之后,你就會有個疑問,發(fā)布和訂閱什么呢?這就需要引入一個新的東西叫主題topic(如果不理解主題這個概念的話也沒關系,后面用代碼就很容易理解主題是什么)

所以它的工作流程就是:

  • subscriber訂閱者連接broker代理,并訂閱主題topic
  • publisher發(fā)布者連接broker代理(當然如何訂閱者和發(fā)布者是同一個Client的話就不需要重復連接),并發(fā)布消息到相應的主題
  • broker代理會把消息發(fā)給對應訂閱的主題的subscriber訂閱者

開發(fā)MQTT通信

1. 處理客戶端和服務端

前面我們說了MQTT是繼續(xù)C/S的結構,那我們就需要有一個客戶端和一個服務端。

(1)服務端開發(fā)

很不幸我是開發(fā)前端的,后臺的開發(fā)我并不熟悉,所以這里的演示中我選擇用云服務EMQX,想嘗試的朋友可以上這個網頁去部署自己的云服務,流程很簡單 cloud.emqx.com/ ,免費試用14天。

(2)客戶端開發(fā)

因為我是做Android開發(fā)的,所以這里我用Android來舉例子。正常來說可以在TCP的基礎上開發(fā),自己去封裝,但我這只是淺談,所以我用第三方框架進行演示,用Paho的mqtt

2. 客戶端開發(fā)

先導入Paho的mqtt

dependencies {
    ......
    implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
    implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
}

在manifest中注冊Paho的MqttService

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.MyApplication">
    <activity
        android:name=".MainActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service android:name="org.eclipse.paho.android.service.MqttService"/>
    <service android:name=".MqttActionService"/>
</application>

我這邊為了用一個項目來演示Mqtt通信,所有把MainActivity當成publisher發(fā)布者,把MqttActionService當成subscriber訂閱者。

所以整體的流程是這樣的,我們先開啟MqttActionService,然后在MqttActionService中進行連接和訂閱。再在MainActivity進行連接和發(fā)送消息。

先把Mqtt的Client給封裝起來(我這里防止有些朋友看不懂Kotlin,我就用了Java,后面不重要的地方我直接用Kotlin,一般也比較容易看懂)。

public class MyMqttClient {
    private MqttAndroidClient mClient;
    private MqttConnectOptions mOptions;
    private OnMqttConnectListener mOnMqttConnectListener;
    private final String mClientId;
    private MqttCallbackExtended mExtended = new MqttCallbackExtended() {
        @Override
        public void connectComplete(boolean reconnect, String serverURI) {
            if (mOnMqttConnectListener != null){
                mOnMqttConnectListener.onConnectComplete(serverURI);
            }
        }
        @Override
        public void connectionLost(Throwable cause) {
            if (mOnMqttConnectListener != null){
                mOnMqttConnectListener.onConnectFailure(cause);
            }
        }
        @Override
        public void messageArrived(String topic, MqttMessage message) throws Exception {
        }
        @Override
        public void deliveryComplete(IMqttDeliveryToken token) {
        }
    };
    private IMqttActionListener mConnectAction = new IMqttActionListener() {
        @Override
        public void onSuccess(IMqttToken asyncActionToken) {
        }
        @Override
        public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
            if (mOnMqttConnectListener != null){
                mOnMqttConnectListener.onConnectFailure(exception);
            }
            exception.printStackTrace();
        }
    };
    private IMqttMessageListener messageListener = new IMqttMessageListener() {
        @Override
        public void messageArrived(String topic, MqttMessage message) throws Exception {
            if (mOnMqttConnectListener != null){
                mOnMqttConnectListener.onMessageArrived(topic, message);
            }
        }
    };
    public MyMqttClient(Context context){
        this(context, null);
    }
    public MyMqttClient(Context context, String clientId){
        if (!TextUtils.isEmpty(clientId)) {
            this.mClientId = clientId;
        }else {
            this.mClientId = MqttConfig.clientId;
        }
        init(context);
    }
    public void init(Context context){
        mClient = new MqttAndroidClient(context, MqttConfig.mqttUrl, mClientId);
        mClient.setCallback(mExtended);
        mOptions = new MqttConnectOptions();
        mOptions.setConnectionTimeout(4000);
        mOptions.setKeepAliveInterval(30);
        mOptions.setUserName(MqttConfig.username);
        mOptions.setPassword(MqttConfig.password.toCharArray());
    }
    public void setOnMqttConnectListener(OnMqttConnectListener onMqttConnectListener) {
        this.mOnMqttConnectListener = onMqttConnectListener;
    }
    /**
     *  連接
     */
    public void connect(){
        try {
            if (!mClient.isConnected()){
                mClient.connect(mOptions, null, mConnectAction);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     *  訂閱
     */
    public void subscribeToTopic(String mTopic){
        this.subscribeToTopic(mTopic, 0);
    }
    public void subscribeToTopic(String mTopic, int qos){
        try {
            mClient.subscribe(mTopic, qos, null,null, messageListener);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     *  發(fā)送消息
     */
    public void sendMessage(String mTopic, byte[] data){
        try {
            MqttMessage message = new MqttMessage();
            message.setPayload(data);
            mClient.publish(mTopic, message);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void onDestroy(){
        try {
            mClient.disconnect();
            mExtended = null;
            mConnectAction = null;
            messageListener = null;
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     *  提供給外層的回調,更方便進行使用
     */
    public interface OnMqttConnectListener{
        void onConnectComplete(String serverURI);
        void onConnectFailure(Throwable e);
        void onMessageArrived(String topic, MqttMessage message);
    }
}

當中有些配置我直接抽出來

public interface MqttConfig {
    String mqttUrl = "tcp://r0c36017.cn-shenzhen.emqx.cloud:11005";
    String clientId = "deployment-r0c36017";
    String username = "yeshuaishizhenshuai";
    String password = "123456";
    String oneTopic = "kylin/topic/one";
}

可以講一下這些參數

(1) mqttUrl: 連接代理的連接,可以看到我上面云服務那張截圖里面的“連接地址”和“連接端口” (2) clientId: 客戶端ID,無論是subscriber還是publisher都屬于客戶端,這個在上面說過,所以都有一個對應的ID標識他們是屬于哪個客戶端。我下面的Demo中MqttActionService用的ClienId是deployment-r0c36017,MainActivity用的ClienId是deployment-r0c36018,不同的,所以是兩個客戶端。 (3) username和password: 這兩個參數都是一個標識,會和后臺記錄,如果你沒有的話,那你就連不上代理,也就是連不上服務端。 (4) oneTopic: 就是主題,你訂閱和發(fā)送消息都要對應是哪個主題。

然后subscriber連接并訂閱主題

class MqttActionService : Service() {
    private var mqttClient : MyMqttClient ?= null
    override fun onCreate() {
        super.onCreate()
        mqttClient = MyMqttClient(this)
        mqttClient?.setOnMqttConnectListener(object : MyMqttClient.OnMqttConnectListener{
            override fun onConnectComplete(serverURI: String?) {
                mqttClient?.subscribeToTopic(MqttConfig.oneTopic)
            }
            override fun onConnectFailure(e: Throwable?) {
            }
            override fun onMessageArrived(topic: String?, message: MqttMessage?) {
                val h = Handler(Looper.getMainLooper())
                h.post {
                    Toast.makeText(this@MqttActionService.applicationContext, message.toString(), Toast.LENGTH_SHORT).show();
                }
            }
        })
    }
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val handler = Handler()
        handler.postDelayed({ mqttClient?.connect() }, 1000)
        return START_STICKY
    }
    override fun onBind(intent: Intent?): IBinder? {
        return null
    }
    override fun onDestroy() {
        super.onDestroy()
        mqttClient?.onDestroy()
    }
}

然后publisher連接并發(fā)送消息

class MainActivity : AppCompatActivity() {
    private var clinet : MyMqttClient ?= null
    private var isConnect = false
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        init()
        val btn : Button = findViewById(R.id.btn_connect)
        val send : Button = findViewById(R.id.btn_send)
        val open : Button = findViewById(R.id.open)
        open.setOnClickListener {
            val intent = Intent()
            intent.setClass(this, MqttActionService::class.java)
            startService(intent)
        }
        btn.setOnClickListener {
            clinet?.connect()
        }
        send.setOnClickListener {
            clinet?.sendMessage(MqttConfig.oneTopic, "你干嘛啊~哎呦~".toByteArray())
        }
    }
    private fun init(){
        clinet = MyMqttClient(this, "deployment-r0c36018")
        clinet?.setOnMqttConnectListener(object : MyMqttClient.OnMqttConnectListener{
            override fun onConnectComplete(serverURI: String?) {
                isConnect = true
            }
            override fun onConnectFailure(e: Throwable?) {
                e?.printStackTrace()
                isConnect = false
            }
            override fun onMessageArrived(topic: String?, message: MqttMessage?) {
            }
        })
    }
}

我這定了3個按鈕,第一個按鈕open會跳轉Service然后subscriber連接并訂閱主題,第二個按鈕btn會連接代理,第三個按鈕send發(fā)送消息。看MqttActionService的代碼可以看出,我這里發(fā)送消息后,會彈出Toast。

Paho的mqtt的BUG

這庫我也是第一次用,我們那用的都是自己擼的(這邊肯定沒法放上來),然后我用的時候發(fā)現一個問題。我想給Service去開一條進程去處理訂閱的操作的,這樣能更真實的去模擬,結果就在連接時出問題了

經檢查,連接的context的進程要和org.eclipse.paho.android.service.MqttService的進程一致。我去看他源碼是怎么回事。

發(fā)現它內部的Binder竟然做了強轉,這里因為不是代理而會出現報錯。如果使用這個庫的話就小心點你要做的夸進程的操作。

總結

今天只是淺談一些MQTT的一些原理和流程,其實還有更深的功能,比如Qos啊這些還沒說,我覺得一次說太多可能會讓第一次接觸的人混亂。先簡單的了解MQTT是什么,主要使用的場景,內部的原理大致是怎樣的。當了解這些之后再去深入的看,會能夠更好的去理解。

以上就是Android開發(fā)MQTT協議的模型及通信淺析的詳細內容,更多關于Android MQTT協議模型通信的資料請關注腳本之家其它相關文章!

相關文章

  • Android仿微信錄制小視頻

    Android仿微信錄制小視頻

    這篇文章主要為大家詳細介紹了Android仿微信錄制小視頻,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • android使用Ultra-PullToRefresh實現下拉刷新自定義代碼

    android使用Ultra-PullToRefresh實現下拉刷新自定義代碼

    本篇文章主要介紹了android使用Ultra-PullToRefresh實現下拉刷新新自定義,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • flutter實現更新彈窗內容例子(親測有效)

    flutter實現更新彈窗內容例子(親測有效)

    Flutter是一款移動應用程序SDK,包含框架、widget和工具,這篇文章給大家介紹flutter實現更新彈窗內容例子,親測可以使用,需要的朋友參考下吧
    2021-04-04
  • Android設計登錄界面、找回密碼、注冊功能

    Android設計登錄界面、找回密碼、注冊功能

    這篇文章主要為大家詳細介紹了Android設計登錄界面的方法,Android實現找回密碼、注冊功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Android OKHttp框架的分發(fā)器與攔截器源碼刨析

    Android OKHttp框架的分發(fā)器與攔截器源碼刨析

    okhttp是一個第三方類庫,用于android中請求網絡。這是一個開源項目,是安卓端最火熱的輕量級框架,由移動支付Square公司貢獻(該公司還貢獻了Picasso和LeakCanary) 。用于替代HttpUrlConnection和Apache HttpClient
    2022-11-11
  • OpenGL Shader實現物件材料效果詳解

    OpenGL Shader實現物件材料效果詳解

    在一些主流app上有一些比較特殊的濾鏡效果,例如灰塵、塑料封面、光影效果等,這些其實是紋理疊加的效果。本文將用OpenGL Shader實現這些效果,需要的可以參考一下
    2022-02-02
  • Android Shader著色器/渲染器的用法解析

    Android Shader著色器/渲染器的用法解析

    這篇文章主要介紹了Android Shader著色器/渲染器的用法解析,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • Android獲得當前正在顯示的activity類名的方法

    Android獲得當前正在顯示的activity類名的方法

    這篇文章主要介紹了Android獲得當前正在顯示的activity類名的方法,分析了權限的修改與Java代碼的實現技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-01-01
  • Android中的全局變量與局部變量使用小結

    Android中的全局變量與局部變量使用小結

    這篇文章主要介紹了Android中的全局變量與局部變量使用小結,聲明一個變量是很 容易的,但是講到使用的時候,卻不是想象的那樣簡單,需要的朋友可以參考下
    2015-06-06
  • 淺談Android單元測試的作用以及簡單示例

    淺談Android單元測試的作用以及簡單示例

    本篇文章主要介紹了淺談Android單元測試的作用以及簡單示例,具有一定的參考價值,有興趣的可以了解一下
    2017-08-08

最新評論