MQTT is so fun, can't you build one yourself?

foreword

I wrote an article before why MQTT is the first choice for smart hardware - Nuggets . This time, I will build my own MQTT interactive platform and experience it in practice. How can it be done without actual combat.

1. Server preparation

1. Choose a platform

The platform I use here is EMQX Cloud . You can apply for an MQTT server for free through a github account. It is very convenient for personal use. At the same time, use the MQTT client to quickly test the MQTT service to monitor or simulate delivery. Here we choose to open it for free. Click Deploy Now and agree all the way and you're done.image.png

2. Start the service

After the establishment, we click on the project management, and there will be a server we just applied for. After entering, click Start, so that we can start the service.image.png image.png

3. Create user

Click Authentication and select Authentication, then click Add on the right to create our connection user. The user name and password are the username and password that our client will need when establishing a connection. So far we can go to the client to write the connection code.image.png

2. Client build

1. Import

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

2. AndroidManifest.xml configuration

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
   ...
   <service android:name="org.eclipse.paho.android.service.MqttService" />
</application>

3. Create an MQTT client

private static MqttAndroidClient mqttAndroidClient;
private static String mqttUsername = ""; //服务端创建的用户名
private static String mqttPassword = ""; //服务端吧创建的用户名密码
private static String clientId = ""; //唯一标识不可重复
 //接受消息的队列
public static final LinkedBlockingQueue<MyMessage> SERVER_QUEUE = new LinkedBlockingQueue<>(
            200);

//消息订阅的topic,可以自定义
private static final String topic = "/" + mqttUsername + "/" + clientId + "/user/get"; 


public static void initIot() {

        String serverUrl = "服务器地址:端口";

        try {
            mqttAndroidClient = new MqttAndroidClient(context, serverUrl, "clientId");

            mqttAndroidClient.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    Log.i(TAG, "连接断开");
                }

                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    Log.i(TAG, "收到消息:" + message.toString());

                    //建议使用队列接收
                    MyMessage myMessage = new MyMessage();
                    myMessage.setData(message.getPayload());
                    boolean offer = SERVER_QUEUE.offer(aMessage);
                    if (!offer) {
                        Log.e(TAG, "队列已满,无法接受消息!");
                    }
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    Log.i(TAG, "deliveryComplete: " + token.toString());

                }
            });

            //建立连接规则
            MqttConnectOptions options = new MqttConnectOptions();
            options.setUserName(mqttUsername);
            options.setPassword(mqttPassword.toCharArray());
            options.setCleanSession(true);
            options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1); //MQTT版本
            options.setConnectionTimeout(10); //连接超时时间
            options.setKeepAliveInterval(180); //心跳间隔时间
            options.setMaxInflight(100); //最大请求数,默认10,高流量场景可以增大该值
            options.setAutomaticReconnect(true); //设置自动重新连接

            mqttAndroidClient.connect(options, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.i(TAG, "连接成功");
                    //这里订阅消息
                    subscribe();
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.i(TAG, "连接失败" + exception);
                }
            });
        } catch (Exception e) {
            Log.e(TAG, "INIT IOT ERROR!");
        }
    }

public class MyMessage {
    
    public Object data;
    
    public MyMessage() {
    }

    public MyMessage(Object data) {
        this.data = data;
    }
    
    public Object getData() {
        return this.data;
    }
    
    public void setData(Object data) {
        this.data = data;
    }
}

4. Subscribe to news

private static void subscribe() {
        try {
            mqttAndroidClient.subscribe(topic, 1, null,
                    new IMqttActionListener() {
                        @Override
                        public void onSuccess(IMqttToken asyncActionToken) {
                            Log.i(TAG,
                                    "订阅成功 topic: "
                                            + topic);
                        }

                        @Override
                        public void onFailure(IMqttToken asyncActionToken,
                                              Throwable exception) {
                            Log.e(TAG, "订阅失败!" + exception.getMessage());
                        }
                    });

        } catch (Exception e) {
            Log.e(TAG, "订阅失败!" + e.getMessage());
        }
    }

5. Post a message

//消息发送队列
public static final LinkedBlockingQueue<String> CLIENT_QUEUE = new LinkedBlockingQueue<>(1000);

//发布消息调用这个方法
public static void putQueue(String msg) {
        boolean offer = CLIENT_QUEUE.offer(msg);
        if (!offer) {
            Log.w(TAG, "操作队列已满!");
        }
    }

//使用线程去读取队列,这样可以防止同一时间多处调用,同时也不会让发送事件丢失
static class IotPublishRunnable implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    String msg = CLIENT_QUEUE.take();
                    if (TextUtils.isEmpty(msg)) {
                        continue;
                    }
                    publish(msg);
                    Thread.sleep(300);
                } catch (Exception e) {
                    Log.e(TAG, "处理iot消息失败");
                }

            }
        }
    }

private static void publishNew(String payload) {
        String topic = "/" + mqttUsername + "/" + clientId + "/user/update";
        Integer qos = 1;

        try {
            if (null == mqttAndroidClient || !mqttAndroidClient.isConnected()) {
                Log.w(TAG, "IOT还未初始化!无法发送消息");
                return;
            }
            mqttAndroidClient.publish(topic, payload.getBytes(StandardCharsets.UTF_8), qos, false,
                    null, new IMqttActionListener() {
                        @Override
                        public void onSuccess(IMqttToken asyncActionToken) {

                        }

                        @Override
                        public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                            String[] topics = asyncActionToken.getTopics();
                            Log.e(TAG, "publish message error! topics: " + Arrays.toString(topics));
                        }
                    });
        } catch (MqttException e) {
            Log.e(TAG, "发送消息失败!");
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "MQTT CLIENT ERROR");
        }
    }

6. Disconnect

public static void disconnect() {
        if (null == mqttAndroidClient || !mqttAndroidClient.isConnected()) {
            Log.w(TAG, "IOT还未初始化!");
            return;
        }

        try {
            mqttAndroidClient.disconnect().setActionCallback(new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.i(TAG, "断开连接成功!");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.i(TAG, "断开连接失败!");
                }
            });
        } catch (MqttException e) {
            Log.e(TAG, e.getMessage());
        }
    }

end

The above is the MQTT code of the client. I wrote it in Java. For the Kotlin version, please refer to Android using Kotlin to connect to MQTT . The code is basically here, and the project will not be released.

Guess you like

Origin juejin.im/post/7239715394369847352