阿里云消息队列MQTT监听客户端状态

项目购买了阿里云消息队列MQTT,为了更好的监听客户端的在线状态,项目使用了MQTT的特性,异步监听客户端的在线状态。但是借鉴阿里云的官方文档,进展不顺利,提工单后,阿里云的客服回复文档说明有误。
这里把在实现中遇到的问题记录下来。

顺便在这里附上官方文档(当前最新的):

RocketMQ: https://help.aliyun.com/product/29530.html

MQTT: https://help.aliyun.com/product/100973.html

1.环境准备,需要购买阿里云的MQTT以及RocketMQ。

2.在阿里云账号控制台找到RocketMQ,选择你所购买的region,创建一个TOPIC,并创建一个GROUP以备用。

3.切换到MQTT,创建一个GROUP,例如:DEVICE-PUSH。

4.在消息存储处,再创建一个主题(DEVICE-PUSH_MQTT),该主题为MQ通知消息主题,设备上下线,都会通知一条消息到该主题下。

服务端的DEMO代码:

public class RocketMQSendMessageToMQ4IoT {
    public static void main(String[] args) throws Exception {
        /**
         * 初始化消息队列 for RocketMQ 发送客户端,实际业务中一般部署在服务端应用中。
         */
        Properties properties = new Properties();
        /**
         * 设置 RocketMQ 客户端的 GroupID,注意此处的 groupId 和 MQ4IoT 实例中的 GroupId 是2个概念,请按照各自产品的说明申请填写
         */
        properties.setProperty(PropertyKeyConst.GROUP_ID, "GID-DEVICE-RocketMQ");
        /**
         * 账号 accesskey,从账号系统控制台获取
         */
        properties.put(PropertyKeyConst.AccessKey, "******");
        /**
         * 账号 secretKey,从账号系统控制台获取,仅在Signature鉴权模式下需要设置
         */
        properties.put(PropertyKeyConst.SecretKey, "******");
        /**
         * 设置 TCP 接入域名
         */
        properties.put(PropertyKeyConst.NAMESRV_ADDR, "*****");
        /**
         * MQ4IoT 和 RocketMQ 配合使用时,RocketMQ 客户端仅操作一级 Topic。
         */
        final String parentTopic = "Payment_Result_Push";

        Producer producer = ONSFactory.createProducer(properties);
        producer.start();

        /**
         *消费者订阅通知消息主题,当设备掉线后,会异步接收该主题的消息。
         *参见官方文档:https://help.aliyun.com/document_detail/50069.html? 
         * spm=a2c4g.11174283.6.551.573e42f001VjiO
        */
        Properties pnroperties = new Properties();
        pnroperties.setProperty(PropertyKeyConst.GROUP_ID, "GID-DEVICE-RocketMQ"); //这里需要添加rocketmq下创建的groupid,不然订阅主题失败。
        pnroperties.put(PropertyKeyConst.AccessKey, "******");
        pnroperties.put(PropertyKeyConst.SecretKey, "******");
        pnroperties.put(PropertyKeyConst.NAMESRV_ADDR, "******");

        properties.put(PropertyKeyConst.MessageModel, PropertyValueConst.CLUSTERING);

        Consumer consumer = ONSFactory.createConsumer(pnroperties);
        consumer.subscribe("GID-DEVICE-PUSH_MQTT", "connect||disconnect||tcpclean", new MessageListener() { //订阅多个 Tag
            public Action consume(Message message, ConsumeContext context) {
                System.out.println(JSONObject.parse(message.getBody()).toString());
                System.out.println("Receive: " + message);
                return Action.CommitMessage;
            }
        });

        consumer.start();
        System.out.println("Consumer Started");
        String clientId = "GID-DEVICE@@@device_sn_1";
        

        for (int i = 0; i < 10; i++) {
            /**
             * 使用 RocketMQ 客户端发消息给 MQ4IoT客户端时,Topic 指定为一级父Topic,Tag指定为 MQ2MQTT
             */
            Message msg = new Message(parentTopic, "MQ2MQTT", "hello mq send mqtt msg".getBytes());

            /**
             * 发送 P2P 消息时,子级 topic如下设置, 具体参考https://help.aliyun.com/document_detail/96176.html?spm=a2c4g.11186623.6.565.10ac1cf7NKGfjI
             */
            msg.putUserProperties(PropertyKeyConst.MqttSecondTopic, "/p2p/" + clientId);
            msg.putUserProperties(PropertyKeyConst.MqttQOS,"1");
            msg.putUserProperties("cleansessionflag","false");
            SendResult result = producer.send(msg);
            System.out.println(result);
        }
        Thread.sleep(1000*30*2);
        producer.shutdown();
        System.out.println("结束");
        System.exit(0);

    }

}

 

客户端代码:

public class MQClient {
    public static void main(String[] args) throws MqttException, InterruptedException, InvalidKeyException, NoSuchAlgorithmException {
        /*
         * MQ4IOT 实例 ID,购买后控制台获取
         */
        String instanceId = "*****";
        /*
         * 接入点地址,购买 MQ4IOT 实例,且配置完成后即可获取,接入点地址必须填写分配的域名,不得使用 IP 地址直接连接,否则可能会导致客户端异常。
         */
        String endPoint = "*****";
        /*
         * 账号 accesskey,从账号系统控制台获取
         */
        String accessKey = "*****";
        /*
         * 账号 secretKey,从账号系统控制台获取,仅在Signature鉴权模式下需要设置
         */
        String secretKey = "*****";
        /*
         * MQ4IOT clientId,由业务系统分配,需要保证每个 tcp 连接都不一样,保证全局唯一,如果不同的客户端对象(tcp 连接)使用了相同的 clientId 会导致连接异常断开。
         * clientId 由两部分组成,格式为 GroupID@@@DeviceId,其中 groupId 在 MQ4IOT 控制台申请,DeviceId 由业务方自己设置,clientId 总长度不得超过64个字符。
         */
        String clientId = "GID-DEVICE-PUSH@@@device_sn_1";
        /*
         * MQ4IOT支持子级 topic,用来做自定义的过滤,此处为示意,可以填写任何字符串,具体参考https://help.aliyun.com/document_detail/42420.html?spm=a2c4g.11186623.6.544.1ea529cfAO5zV3
         * 需要注意的是,完整的 topic 长度不得超过128个字符。
         */
        //final String subTopic = "/mq4Iot";
        final String mq4IotTopic = "****" ;     //在rocketmq端创建的TOPIC
        /*
         * QoS参数代表传输质量,可选0,1,2,根据实际需求合理设置,具体参考 https://help.aliyun.com/document_detail/42420.html?spm=a2c4g.11186623.6.544.1ea529cfAO5zV3
         */
        final int qosLevel = 1;
        ConnectionOptionWrapper connectionOptionWrapper = new ConnectionOptionWrapper(instanceId, accessKey, secretKey, clientId);
        final MemoryPersistence memoryPersistence = new MemoryPersistence();
        /*
         * 客户端使用的协议和端口必须匹配,具体参考文档 https://help.aliyun.com/document_detail/44866.html?spm=a2c4g.11186623.6.552.25302386RcuYFB
         * 如果是 SSL 加密则设置ssl://endpoint:8883
         */
        final MqttClient mqttClient = new MqttClient("tcp://" + endPoint + ":1883", clientId, memoryPersistence);
        /*
         * 客户端设置好发送超时时间,防止无限阻塞
         */
        mqttClient.setTimeToWait(5000);
        final ExecutorService executorService = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
        mqttClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {
                /**
                 * 客户端连接成功后就需要尽快订阅需要的 topic
                 */
                System.out.println("connect success");
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            final String topicFilter[] = {mq4IotTopic};
                            final int[] qos = {qosLevel};
                            mqttClient.subscribe(topicFilter, qos);
                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }

            @Override
            public void connectionLost(Throwable throwable) {
                throwable.printStackTrace();
            }

            @Override
            public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
                /**
                 * 消费消息的回调接口,需要确保该接口不抛异常,该接口运行返回即代表消息消费成功。
                 * 消费消息需要保证在规定时间内完成,如果消费耗时超过服务端约定的超时时间,对于可靠传输的模式,服务端可能会重试推送,业务需要做好幂等去重处理。超时时间约定参考限制
                 * https://help.aliyun.com/document_detail/63620.html?spm=a2c4g.11186623.6.546.229f1f6ago55Fj
                 */
                System.out.println(
                        "receive msg from topic " + s + " , body is " + new String(mqttMessage.getPayload()));
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
                System.out.println("send msg succeed topic is : " + iMqttDeliveryToken.getTopics()[0]);
            }
        });
        mqttClient.connect(connectionOptionWrapper.getMqttConnectOptions());
        Thread.sleep(1000*60*60);
    }
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值