MQTT简单demo(java)

33 篇文章 0 订阅
20 篇文章 0 订阅
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_38533859/article/details/82193729

  上次已经简单的谈了一些MQTT协议的一些知识,今天就来就上次的知识具体的Java实现。

  现在就来具体说说实现这一步吧。中间的时间也是有点久。

  MQTT消息的发送和订阅都是依赖MQTT服务器的,没有MQTT服务器,你的客户端是无法订阅和发送消息的。所以在最开始的时候,可以选择性的在你的电脑上面安装一个MQTT服务器。MQTT服务器有很多,大家也可以在网上去找一些安装教程,这里因为和我要讲内容关系不大,所以不再累述。

  MQTT协议中是没有发送者和接收者·的概念,所有的连接都是用户,所以一个MQTT连接既可以发送消息,也可以接收消息。就等于所有的连接都是客户端。下面我的客户端代码也是如此,因为公司这边接收的信息先是要进行认证,认证成功后再接收有用的信息。这时,客户端在根据设备的信息来控制网关上面的设备,达到远程控制设备的目的。因为要使用服务器来转发消息,所以对于服务器的测试也是比较重要的,但是我使用的是公司的服务器,所以这一块我的了解比较少。但是我这边有一些工具,谷歌浏览器的插件MQTTLens。可能会帮助你。(需要翻阅墙体)

  MQTT使用的库也是有很多的,下面的网址也是列举了MQTT支持的库,有java的,也有c的。网址如下:https://github.com/mqtt/mqtt.github.io/wiki/libraries。因为最开始我的接触还是比较浅,使用的是:Fusesource mqtt-client。所以java的demo也是基于这个库的,但是后来和spring整合的时候发现有一些问题,因为spring支持的只有一个库,就是Eclipse Paho Java。但是原理都是一样的,大家可以自己去决定,我的简单的demo代码还是基于Fusesource mqtt-client。在下一篇Spring和MQTT整合中使用的是Eclipse Paho Java

  下面就说一说具体的思路,这边我的代码是基于公司的网关需求,所以先说一说公司网关的具体流程。首先,网关会一直发送身份验证消息,等待客户端认证,客户端认证通过后,会发送具体有用的信息。客户端这时在根据网关信息发送控制命令,到达控制的目的。在这个过程中,客户端有订阅和发送,所以一个客户端就练习了发送消息和订阅消息。这就是公司的具体操作流程。下面就说一说代码的流程。

  运行时要使用jar包,也可使用maven,但是使用maven时要注意版本。

  具体的jar包和maven依赖在网址:https://gitee.com/iots/mqtt-client

  依赖为:


 
 
  1. <dependency>
  2. <groupId>org.fusesource.mqtt-client </groupId>
  3. <artifactId>mqtt-client </artifactId>
  4. <version>1.12 </version>
  5. </dependency>

       下面开始编写demo

       首先先要配置MQTT的一些配置,配置比较多,也很繁琐。

主要是配置主机号和端口号,根据自己的配置编写代码,在配置其他的一些细节配置,主要是和连接有关的。

  代码如下:             


 
 
  1. // MQTT设置说明
  2. // 设置主机号
  3. mqtt.setHost( "服务器地址和端口号");
  4. // 用于设置客户端会话的ID。在setCleanSession(false);被调用时,MQTT服务器利用该ID获得相应的会话。此ID应少于23个字符,默认根据本机地址、端口和时间自动生成
  5. mqtt.setClientId( "876543210");
  6. // 若设为false,MQTT服务器将持久化客户端会话的主体订阅和ACK位置,默认为true
  7. mqtt.setCleanSession( false);
  8. // 定义客户端传来消息的最大时间间隔秒数,服务器可以据此判断与客户端的连接是否已经断开,从而避免TCP/IP超时的长时间等待
  9. mqtt.setKeepAlive(( short) 60);
  10. // 服务器认证用户名
  11. mqtt.setUserName( "admin");
  12. // 服务器认证密码
  13. mqtt.setPassword( "admin");
  14. // 设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息
  15. mqtt.setWillTopic( "willTopic");
  16. // 设置“遗嘱”消息的内容,默认是长度为零的消息
  17. mqtt.setWillMessage( "willMessage");
  18. // 设置“遗嘱”消息的QoS,默认为QoS.ATMOSTONCE
  19. mqtt.setWillQos(QoS.AT_LEAST_ONCE);
  20. // 若想要在发布“遗嘱”消息时拥有retain选项,则为true
  21. mqtt.setWillRetain( true);
  22. // 设置版本
  23. mqtt.setVersion( "3.1.1");
  24. // 失败重连接设置说明
  25. // 客户端首次连接到服务器时,连接的最大重试次数,超出该次数客户端将返回错误。-1意为无重试上限,默认为-1
  26. mqtt.setConnectAttemptsMax( 10L);
  27. // 客户端已经连接到服务器,但因某种原因连接断开时的最大重试次数,超出该次数客户端将返回错误。-1意为无重试上限,默认为-1
  28. mqtt.setReconnectAttemptsMax( 3L);
  29. // 首次重连接间隔毫秒数,默认为10ms
  30. mqtt.setReconnectDelay( 10L);
  31. // 重连接间隔毫秒数,默认为30000ms
  32. mqtt.setReconnectDelayMax( 30000L);
  33. // 设置重连接指数回归。设置为1则停用指数回归,默认为2
  34. mqtt.setReconnectBackOffMultiplier( 2);
  35. // Socket设置说明
  36. // 设置socket接收缓冲区大小,默认为65536(64k)
  37. mqtt.setReceiveBufferSize( 65536);
  38. // 设置socket发送缓冲区大小,默认为65536(64k)
  39. mqtt.setSendBufferSize( 65536);
  40. // 设置发送数据包头的流量类型或服务类型字段,默认为8,意为吞吐量最大化传输
  41. mqtt.setTrafficClass( 8);
  42. // 带宽限制设置说明
  43. // 设置连接的最大接收速率,单位为bytes/s。默认为0,即无限制
  44. mqtt.setMaxReadRate( 0);
  45. // 设置连接的最大发送速率,单位为bytes/s。默认为0,即无限制
  46. mqtt.setMaxWriteRate( 0);
  47. // 选择消息分发队列
  48. // 若没有调用方法setDispatchQueue,客户端将为连接新建一个队列。如果想实现多个连接使用公用的队列,显式地指定队列是一个非常方便的实现方法
  49. mqtt.setDispatchQueue(Dispatch.createQueue( "foo"));

  上面都是一些配置的问题,具体情况自己决定配置。具体的配置也可以参考下面的网址,这个网址也有详细的描述:https://gitee.com/iots/mqtt-client。

  下面开始讲讲连接和订阅和发送主题

  fusesource提供三种mqtt client api,分别为阻塞API,基于Futur的API和回调API。

  其中阻塞API是在MQTT.connectBlocking方法建立连接和提供阻断API的连接。

  基于Futur的API则是:在MQTT.connectFuture方法建立连接,为您提供了一个与结合Futur的连接。所有操作的连接是无阻塞的,并且经由返回的结果。

  回调API是最复杂的也是性能最好的,另外两种均是对回调API的封装。

  因为回调API有些复杂,现在只是介绍回调API的封装。就是前两个,前两个的区别是第一个为阻塞的,第二个不是阻塞。下面开始代码演示。

  第一个阻塞API。代码如下:     


 
 
  1. // 接收消息
  2. Message message = connection.receive();
  3. // 将收到的消息封装为消息类
  4. ReceiveRealValiedateVO realValiedateVO = JSON.parseObject(message.getPayloadBuffer().toByteArray(),
  5. ReceiveRealValiedateVO.class);
  6. System. out.println(realValiedateVO.getG_id());
  7. if (realValiedateVO.getS_id(). equals( "1") && realValiedateVO.getS_id(). equals( "1")) {
  8. // 新建json
  9. JSONObject jsonParam = new JSONObject();
  10. // 封装json
  11. jsonParam.put( "s_id", realValiedateVO.getS_id());
  12. jsonParam.put( "g_id", realValiedateVO.getG_id());
  13. jsonParam.put( "seq", realValiedateVO.getSeq());
  14. jsonParam.put( "type", realValiedateVO.getType());
  15. jsonParam.put( "valid", "true");
  16. String s = jsonParam.toString();
  17. // 发送特定主题的消息
  18. connection.publish( "主題", s.getBytes(), QoS.AT_LEAST_ONCE, false);
  19. }
  20. // 打印主题
  21. System. out.println(message.getTopic());
  22. // byte[] payload = message.getPayload();
  23. System. out.println(String.valueOf(message.getPayloadBuffer()));
  24. // process the message then:
  25. message.ack();
  26. // 连接断开
  27. // connection.disconnect();

  具体的解释都在代码里了,剩下就没有什么了。

  要注意的点就是连接中断的处理,和对于服务器的处理。

  第二种就是使用future连接,代码如下:


 
 
  1. // 使用future连接
  2. FutureConnection connection = mqtt.futureConnection();
  3. Future<Void> f1 = connection.connect();
  4. f1. await();
  5. // 订阅消息
  6. Future< byte[]> f2 = connection.subscribe( new Topic[] { new Topic( "主题", QoS.AT_LEAST_ONCE) });
  7. //
  8. byte[] qoses = f2. await();
  9. // 发送身份验证消息.
  10. // Future<Void> f3 = connection.publish("foo", "Hello".getBytes(),
  11. // QoS.AT_LEAST_ONCE, false);
  12. // 接收订阅消息..
  13. Future<Message> receive = connection.receive();
  14. // 打印消息.
  15. Message message = receive. await();
  16. System. out.println(String.valueOf(message.getPayloadBuffer()));
  17. // 回应
  18. message.ack();
  19. //
  20. Future<Void> f4 = connection.disconnect();
  21. f4. await();

  第三个是最难的,我这边的代码也是有点乱,直接上代码吧。


 
 
  1. // 监听
  2. connection.listener( new Listener() {
  3. @ Override
  4. public void onPublish( UTF8Buffer topicmsg, Buffer msg, Runnable ack) {
  5. // utf-8 is used for dealing with the garbled
  6. String topic = topicmsg.utf8().toString();
  7. String payload = msg.utf8().toString();
  8. System. out.println(topic + " " + payload);
  9. String Amsg = AuthenticationSendDemo.Authentication(topic, payload);
  10. if (topic. equals( "主题")) {
  11. // 重起一个阻塞线程
  12. connection.getDispatchQueue().execute( new Runnable() {
  13. public void run() {
  14. connection.publish( "主题", Amsg.getBytes(), QoS.AT_LEAST_ONCE, false,
  15. new Callback<Void>() {
  16. @ Override
  17. public void onSuccess( Void args) {
  18. // 表示发布主题成功
  19. System. out.println( "发布成功!");
  20. System. out.println( "发布的消息" + Amsg);
  21. }
  22. @ Override
  23. public void onFailure( Throwable throwable) {
  24. // 表示发布主题失败
  25. System. out.println( "发布失败!");
  26. }
  27. });
  28. }
  29. });
  30. }
  31. // 表示监听成功
  32. ack.run();
  33. }
  34. @ Override
  35. public void onFailure( Throwable value) {
  36. // 表示监听失败
  37. }
  38. // execute only once when connection is ended
  39. @ Override
  40. public void onDisconnected( ) {
  41. // 表示监听到断开连接
  42. System. out.println( "断开连接!!");
  43. }
  44. // execute only once when connecting started
  45. @ Override
  46. public void onConnected( ) {
  47. // 表示监听到连接成功
  48. System. out.println( "haha");
  49. System. out.println();
  50. }
  51. });

  因为代码中使用到了线程和回调,我对于这两个掌握的也不是很好,也不再这里乱扯,有大佬知道比较好的写法最好指点一下。在这里感谢。

  三种写法都写完了,下面谈一谈感想和中间遇到的问题。

  以为看具体的文档实在太多了,现在公司还在忙着赶项目,我这边时间也不是很多,代码的整理以后有时间在说。我感觉最重要的还是对于协议的一些掌握和体会,这些要比上面的代码重要的多,因为你最终的代码还是要和项目整合的,和Spring整合的时候你会发现这些都是框架提供好了,你需要做的就是填参数,但是整合中遇到的问题的解决办法都是你从写上面的代码中得到的。

因为刚开始写代码,所以代码中的注释也是非常多的,这里也不再累述。写上面的代码的时候遇到了很多的问题,解决的网站都在我第一篇MQTT博客中,比如MQTT的官网,网上的文章都是抄的,要不就是一知半解(我也是)。最终还是看自己的深入体会。

  就这样吧,结束。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值