MQTT是一款针对机对机(M2M)通信的,非常轻量级的的消息订阅、发布协议。它适用于一些系统资源和网络带宽非常有限的情况下的远程连接。MQTT-Client提供一个ASL 2.0证书下的MQTT接口。在网络连接失败时,它能够自动地重新连接服务器并尝试恢复会话。应用程序能够使用阻塞API、基于Future的API和回调API,共三种接口形式。

 

在Maven中引用MQTT-Client

将下列文本加入到pom.xml文件中。

Xml代码
  1. <dependency>
  2. <groupId>org.fusesource.mqtt-clientgroupId>
  3. <artifactId>mqtt-clientartifactId>
  4. <version>1.0-SNAPSHOTversion>
  5. dependency>
  6.  
  7. <repositories>
  8. <repository>
  9. <id>fusesource.snapshotsid>
  10. <name>FuseSource Snapshot Repositoryname>
  11. <url>http://repo.fusesource.com/nexus/content/repositories/snapshotsurl>
  12. <snapshots><enabled>trueenabled>snapshots>
  13. <releases><enabled>falseenabled>releases>
  14. repository>
  15. repositories>

 

以其他方式引用MQTT-Client

下载uber jar文件并加入编译路径中,该jar文件中包含MQTT-Client的所有依赖。

在Java 1.4环境中使用

作者同时提供了适用于Java 1.4的API。由于Java1.4中没有SSLEngine类依赖的NIO,因此该API不支持SSL连接。

 

配置MQTT连接

前面提到的阻塞、Future和回调这3种API,建立连接时使用的代码时完全相同的。首先新建一个MQTT对象并配置连接参数。在连接前至少要调用setHost方法,来指定所要连接的服务器地址。

Java代码
  1. MQTT mqtt = new MQTT();
  2. mqtt.setHost("localhost", 1883);
  3. // or
  4. mqtt.setHost("tcp://localhost:1883");

 

MQTT设置说明

  • setClientId:用于设置客户端会话的ID。在setCleanSession(false);被调用时,MQTT服务器利用该ID获得相应的会话。此ID应少于23个字符,默认根据本机地址、端口和时间自动生成。
  • setCleanSession:若设为false,MQTT服务器将持久化客户端会话的主体订阅和ACK位置,默认为true。
  • setKeepAlive:定义客户端传来消息的最大时间间隔秒数,服务器可以据此判断与客户端的连接是否已经断开,从而避免TCP/IP超时的长时间等待。
  • setUserName:服务器认证用户名。
  • setPassword:服务器认证密码。
  • setWillTopic:设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息。
  • setWillMessage:设置“遗嘱”消息的内容,默认是长度为零的消息。
  • setWillQos:设置“遗嘱”消息的QoS,默认为QoS.ATMOSTONCE。
  • setWillRetain:若想要在发布“遗嘱”消息时拥有retain选项,则为true。

失败重连接设置说明

网络出现故障时,程序能够自动重新连接并重建会话。利用下列方法能够配置重新连接的间隔和最大重试次数:

  • setConnectAttemptsMax:客户端首次连接到服务器时,连接的最大重试次数,超出该次数客户端将返回错误。-1意为无重试上限,默认为-1。
  • setReconnectAttemptsMax:客户端已经连接到服务器,但因某种原因连接断开时的最大重试次数,超出该次数客户端将返回错误。-1意为无重试上限,默认为-1。
  • setReconnectDelay:首次重连接间隔毫秒数,默认为10ms。
  • setReconnectDelayMax:重连接间隔毫秒数,默认为30000ms。
  • setReconnectBackOffMultiplier:设置重连接指数回归。设置为1则停用指数回归,默认为2。

Socket设置说明

可以利用下列方法调整socket设置:

  • setReceiveBufferSize:设置socket接收缓冲区大小,默认为65536(64k)。

  • setSendBufferSize:设置socket发送缓冲区大小,默认为65536(64k)。

  • setTrafficClass:设置发送数据包头的流量类型或服务类型字段,默认为8,意为吞吐量最大化传输。

带宽限制设置说明

可通过下述方法设置读写速率限制:

  • setMaxReadRate:设置连接的最大接收速率,单位为bytes/s。默认为0,即无限制。

  • setMaxWriteRate:设置连接的最大发送速率,单位为bytes/s。默认为0,即无限制。

使用SSL连接

如果想使用SSL/TLS连接,替代TCP连接,可以使用“ssl://”或“tls://”作为连接URI前缀,实现安全连接。支持的协议包括:

  • ssl:// - 使用JVM默认版本的SSL算法。
  • sslv*:// - 使用指定版本的SSL算法,星号为JVM支持的SSL算法版本,例如sslv3
  • tls:// - 使用JVM默认版本的TLS算法。
  • tlsv*:// - 使用指定版本的TLS算法,星号为JVM支持的TLS算法版本,例如tlsv1.1

客户端使用JVM的SSLContext,基于在JVM的系统配置进行连接。可以调用MQTT的setSslContext方法,换用其他连接方式。
对于内部线程池,SSL连接为阻塞特性。调用setBlockingExecutor方法可以替换所要使用的executor。

选择消息分发队列

若没有调用方法setDispatchQueue,客户端将为连接新建一个队列。如果想实现多个连接使用公用的队列,显式地指定队列是一个非常方便的实现方法。

使用阻塞API

MQTT.connectBlocking方法建立并返回一个阻塞API连接。

Java代码
  1. BlockingConnection connection = mqtt.blockingConnection();
  2. connection.connect();

使用publish方法发布消息:

Java代码
  1. connection.publish("foo", "Hello".toBytes(), QoS.AT_LEAST_ONCE, false);

可以利用subscribe方法订阅多个主题:

Java代码
  1. Topic[] topics = {new Topic("foo", QoS.AT_LEAST_ONCE)};
  2. byte[] qoses = connection.subscribe(topics);

利用receive和ack方法,获取并应答消息:

Java代码
  1. Message message = connection.receive();
  2. System.out.println(message.getTopic());
  3. byte[] payload = message.getPayload();
  4. // process the message then:
  5. message.ack();

结束连接:

Java代码
  1. connection.disconnect();

 

使用基于Future的API

MQTT.connectFuture方法建立并返回一个基于Future类型的API连接。所有连接操作都是非阻塞的,连接结果通过Future对象返回

Java代码
  1. FutureConnection connection = mqtt.futureConnection();
  2. Future f1 = connection.connect();
  3. f1.await();
  4.  
  5. Future<byte[]> f2 = connection.subscribe(new Topic[]{new Topic(utf8("foo"), QoS.AT_LEAST_ONCE)});
  6. byte[] qoses = f2.await();
  7.  
  8. // We can start future receive..
  9. Future receive = connection.receive();
  10.  
  11. // send the message..
  12. Future f3 = connection.publish("foo", "Hello".getBytes(), QoS.AT_LEAST_ONCE, false);
  13.  
  14. // Then the receive will get the message.
  15. Message message = receive.await();
  16. message.ack();
  17.  
  18. Future f4 connection.disconnect();
  19. f4.await();

使用回调API

MQTT.connectCallback方法建立并返回一个回调API连接。本方法是三种API中最复杂也是性能最好的API,前面提到的两种API其实都是对回调API的封装。对连接的所有操作都是非阻塞的,返回的结果将传至回调接口函数。示例如下

Java代码
  1. final CallbackConnection connection = mqtt.callbackConnection();
  2. connection.listener(new Listener() {
  3.  
  4. public void onDisconnected() {
  5. }
  6. public void onConnected() {
  7. }
  8.  
  9. public void onSuccess(UTF8Buffer topic, Buffer payload, Runnable ack) {
  10. // You can now process a received message from a topic.
  11. // Once process execute the ack runnable.
  12. ack.run();
  13. }
  14. public void onFailure(Throwable value) {
  15. connection.close(null); // a connection failure occured.
  16. }
  17. })
  18. connection.connect(new Callback() {
  19. public void onFailure(Throwable value) {
  20. result.failure(value); // If we could not connect to the server.
  21. }
  22.  
  23. // Once we connect..
  24. public void onSuccess(Void v) {
  25.  
  26. // Subscribe to a topic
  27. Topic[] topics = {new Topic("foo", QoS.AT_LEAST_ONCE)};
  28. connection.subscribe(topics, new Callback<byte[]>() {
  29. public void onSuccess(byte[] qoses) {
  30. // The result of the subcribe request.
  31. }
  32. public void onFailure(Throwable value) {
  33. connection.close(null); // subscribe failed.
  34. }
  35. });
  36.  
  37. // Send a message to a topic
  38. connection.publish("foo", "Hello".getBytes(), QoS.AT_LEAST_ONCE, false, new Callback() {
  39. public void onSuccess(Void v) {
  40. // the pubish operation completed successfully.
  41. }
  42. public void onFailure(Throwable value) {
  43. connection.close(null); // publish failed.
  44. }
  45. });
  46.  
  47. // To disconnect..
  48. connection.disconnect(new Callback() {
  49. public void onSuccess(Void v) {
  50. // called once the connection is disconnected.
  51. }
  52. public void onFailure(Throwable value) {
  53. // Disconnects never fail.
  54. }
  55. });
  56. }
  57. });

Every connection has a HawtDispatch dispatch queue which it uses to process IO events for the socket. The dispatch queue is an Executor that provides serial execution of IO and processing events and is used to ensure synchronized access of connection.

The callbacks will be executing the the the dispatch queue associated with the connection so it safe to use the connection from the callback but you MUST NOT perform any blocking operations within the callback. If you need to perform some processing which MAY block, you must send it to another thread pool for processing. Furthermore, if another thread needs to interact with the connection it can only doit by using a Runnable submitted to the connection's dispatch queue.

Example of executing a Runnable on the connection's dispatch queue:

Java代码
  1. connection.getDispatchQueue().execute(new Runnable(){
  2. public void run() {
  3. connection.publish( ..... );
  4. }
  5. });