----- ## 目录 * 1 MQTT的协议说明 * 2 Mosquitto的安装和部署 * 3 Mosquitto的集群部署 * 4 Mosquitto的账号和权限 * 5 Mosquitto的TLS连接方式 * 6 Mosquitto的JAVA客户端使用 * 7 Mosquitto的性能测试 ------- ## 1 MQTT的协议说明 详细请参考: [MQTT协议中文文档](https://mcxiaoke.gitbooks.io/mqtt-cn/content/) MQTT是一个客户端服务端架构的发布/订阅模式的<font color=red>消息传输协议</font>。它的设计思想是轻巧、开放、简单、规范,易于实现。这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器的通信(M2M)以及物联网环境(IoT)。 本协议运行在TCP/IP,或其它提供了有序、可靠、双向连接的网络连接上。它有以下特点: - 使用发布/订阅消息模式,提供了一对多的消息分发和应用之间的解耦。 - 消息传输不需要知道负载内容。 - 提供三种等级的服务质量:. - “最多一次”,尽操作环境所能提供的最大努力分发消息。消息可能会丢失。例如,这个等级可用于环境传感器数据,单次的数据丢失没关系,因为不久之后会再次发送。 - “至少一次”,保证消息可以到达,但是可能会重复。 - “仅一次”,保证消息只到达一次。例如,这个等级可用在一个计费系统中,这里如果消息重复或丢失会导致不正确的收费。 - 很小的传输消耗和协议数据交换,最大限度减少网络流量 - 异常连接断开发生时,能通知到相关各方。 **1.1 网络连接 Network Connection** 1.1.1 MQTT使用的底层传输协议基础设施。 - 客户端使用它连接服务端。 - 它提供有序的、可靠的、双向字节流传输。 1.1.2 MQTT支持协议 - TCP/IP协议 URI的scheme “tcp:” - TLS协议 URI的scheme “tls:” 或 “ssl:” - WebSocket协议 URI的scheme “ws:” 1.1.3 连接过程 - 由CONNECT报文控制连接 连接参数 - MQTT为固定的协议名,3.1.1版协议的协议级别字段的值是4(0x04) - 会话清理:当声明为false时,会自动恢复上一次的回话状态,注意此时client id 客户端ID必不为空,否则无法识别 - 连接信息中Will的设置会在离线时发出通知,适合用于连接断开的判断 - UserName和PassWord用于做用户的身份认证,需要结合ssl/tls一起使用,否则将以明文的形式暴露在网络环境中 - CONNECT接收后的处理 连接成功场景 如果ClientId表明客户端已经连接到这个服务端,那么服务端必须断开原有的客户端连接 服务端必须发送返回码为零的CONNACK报文作为CONNECT报文的确认响应 连接失败场景 服务端可以检查CONNECT报文的内容是不是满足任何进一步的限制,可以执行身份验证和授权检查。 如果任何一项检查没通过,应该发送一个适当的、返回码非零的CONNACK响应,并且必须关闭这个网络连接。 - CONNECT异常场景 1、在一个网络连接上,客户端只能发送一次CONNECT报文。服务端必须将客户端发送的第二个CONNECT报文当作协议违规处理并断开客户端的连接 [MQTT-3.1.0-2] 2、连接时如果协议名不正确服务端可以断开客户端的连接,也可以按照某些其它规范继续处理CONNECT报文 3、对于3.1.1版协议,协议级别字段的值是4(0x04)。如果发现不支持的协议级别,服务端必须给发送一个返回码为0x01(不支持的协议级别)的CONNACK报文响应CONNECT报文,然后断开客户端的连接 [MQTT-3.1.2-2]。 - CONNACK的异常响应码 0 | 0x00连接已接受 | 连接已被服务端接受 | 1 | 0x01连接已拒绝,不支持的协议版本 | 服务端不支持客户端请求的MQTT协议级别 | 2 | 0x02连接已拒绝,不合格的客户端标识符 | 客户端标识符是正确的UTF-8编码,但服务端不允许使用 | 3 | 0x03连接已拒绝,服务端不可用 | 网络连接已建立,但MQTT服务不可用 | 4 | 0x04连接已拒绝,无效的用户名或密码 | 用户名或密码的数据格式无效 | 5 | 0x05连接已拒绝,未授权 | 客户端未被授权连接到此服务器 | | 6-255 | | 保留 | 如果认为上表中的所有连接返回码都不太合适,那么服务端必须关闭网络连接,不需要发送CONNACK报文 [MQTT-3.2.2-6]。 **1.2 应用消息 Application Message** MQTT协议通过网络传输应用数据。应用消息通过MQTT传输时,它们有关联的服务质量(QoS)和主题(Topic)。 1.2.1 QoS定义 QoS值:0 最多分发一次 QoS值:1 至少分发一次 QoS值:2 只分发一次 1.2.2 topic规则和设置 - 主题层级分隔符—“/” 主题层级分隔符使得主题名结构化。如果存在分隔符,它将主题名分割为多个主题层级。斜杠(‘/’ U+002F)用于分割主题的每个层级,为主题名提供一个分层结构。当客户端订阅指定的主题过滤器包含两种通配符时,主题层级分隔符就很有用了。主题层级分隔符可以出现在主题过滤器或主题名字的任何位置。相邻的主题层次分隔符表示一个零长度的主题层级。 - 多层通配符—“#” “#”是用于匹配主题中任意层级的通配符。多层通配符表示它的父级和任意数量的子层级。多层通配符必须位于它自己的层级或者跟在主题层级分隔符后面。不管哪种情况,它都<font color='red'>必须是主题过滤器的最后一个字符</font>。 - 单层通配符—“+” 加号是只能用于单个主题层级匹配的通配符。在主题过滤器的任意层级都可以使用单层通配符,包括第一个和最后一个层级。然而它必须占据过滤器的整个层级 。可以在主题过滤器中的多个层级中使用它,也可以和多层通配符一起使用。 - 系统消息通配符 —“$” 常见于“$SYS/” 系统消息主题 [更详细的说明](https://blog.csdn.net/qq_28877125/article/details/78360376) 1.2.3 retain关键字的说明 如果客户端发给服务端的PUBLISH报文的保留(RETAIN)标志被设置为1,服务端必须存储这个应用消息和它的服务质量等级(QoS),以便它可以被分发给未来的主题名匹配的订阅者 [MQTT-3.3.1-5]。一个新的订阅建立时,对每个匹配的主题名,如果存在最近保留的消息,它必须被发送给这个订阅者 [MQTT-3.3.1-6]。如果服务端收到一条保留(RETAIN)标志为1的QoS 0消息,它必须丢弃之前为那个主题保留的任何消息。它应该将这个新的QoS 0消息当作那个主题的新保留消息,但是任何时候都可以选择丢弃它 — 如果这种情况发生了,那个主题将没有保留消息 [MQTT-3.3.1-7]。有关存储状态的更多信息见 4.1节。 <font color='red'>注意:retain关键字设置为true时,当设置QoS > 0的场景,后发的消息将不被保存,当设置QoS = 0的场景,后发的消息将替换之前的消息。 MQTT不支持消息存储,针对每一个通道,只保留最多一条消息,如果错过了消费,就会被丢弃,所以消费者不能被关闭,否则消息将发生丢失 </font> **1.3 客户端 Client** 使用MQTT的程序或设备。客户端总是通过网络连接到服务端。它可以 - 发布应用消息给其它相关的客户端。 - 订阅以请求接受相关的应用消息。 - 取消订阅以移除接受应用消息的请求。 - 从服务端断开连接。 1.3.1 订阅主题 客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅。每个订阅注册客户端关心的一个或多个主题。为了将应用消息转发给与那些订阅匹配的主题,服务端发送PUBLISH报文给客户端。SUBSCRIBE报文也(为每个订阅)指定了最大的QoS等级,服务端根据这个发送应用消息给客户端。 1.3.2 订阅过程 客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅。每个订阅注册客户端关心的一个或多个主题。为了将应用消息转发给与那些订阅匹配的主题,服务端发送PUBLISH报文给客户端。SUBSCRIBE报文也(为每个订阅)指定了最大的QoS等级,服务端根据这个发送应用消息给客户端。 SUBSCRIBE – 订阅主题 SUBACK – 订阅确认 注意:订阅的QoS和发布的QoS可能不一致,订阅方的QoS等级高于发布方的QoS等级时,将被服务降级 1.3.3 取消订阅 客户端发送UNSUBSCRIBE报文给服务端,用于取消订阅主 UNSUBSCRIBE – 取消订阅 UNSUBACK – 取消订阅确认 **1.4 服务端 Server** 一个程序或设备,作为发送消息的客户端和请求订阅的客户端之间的中介。服务端 - 接受来自客户端的网络连接。 - 接受客户端发布的应用消息。 - 处理客户端的订阅和取消订阅请求。 - 转发应用消息给符合条件的已订阅客户端。 1.4.1 消息发布过程 PUBLISH – 发布消息 PUBACK – 发布确认 PUBREC – 发布收到 PUBREL – 发布释放 PUBCOMP – 发布完成 **1.5 心跳机制 PING** 1.5.1 PINGREQ – 心跳请求 客户端发送PINGREQ报文给服务端的。用于: 1. 在没有任何其它控制报文从客户端发给服务的时,告知服务端客户端还活着。 2. 请求服务端发送 响应确认它还活着。 3. 使用网络以确认网络连接没有断开。 1.5.2 PINGRESP – 心跳响应 服务端发送PINGRESP报文响应客户端的PINGREQ报文。表示服务端还活着。 **1.6 断开连接 DISCONNECT** DISCONNECT报文是客户端发给服务端的最后一个控制报文。表示客户端正常断开连接。 1.6.1 客户端发送DISCONNECT报文之后: * 必须关闭网络连接 [MQTT-3.14.4-1]。 * 不能通过那个网络连接再发送任何控制报文 [MQTT-3.14.4-2]。 1.6.2 服务端在收到DISCONNECT报文时: * 必须丢弃任何与当前连接关联的未发布的遗嘱消息,具体描述见 3.1.2.5节 [MQTT-3.14.4-3]。 * 应该关闭网络连接,如果客户端 还没有这么做。 **1.7 状态存储 Storing state** 为了提供服务质量保证,客户端和服务端有必要存储会话状态。在整个会话期间,客户端和服务端都**必须**存储会话状态 \[MQTT-4.1.0-1\]。会话**必须**至少持续和它的活跃网络连接同样长的时间 \[MQTT-4.1.0-2\]。 服务端的保留消息不是会话状态的组成部分。服务端**应该**保留那种消息直到客户端删除它。 状态通过ClientId来维持,是对Session的存储 ----- ## 2 Mosquitto的安装和部署 ### 2.1 Mosquitto的简介 一款实现了消息推送协议 MQTT v3.1 的开源消息代理软件,提供轻量级的,支持可发布/可订阅的的消息推送模式,使设备对设备之间的短消息通信变得简单,比如现在应用广泛的低功耗传感器,手机、嵌入式计算机、微型控制器等移动设备。一个典型的应用案例就是 Andy Stanford-ClarkMosquitto(MQTT协议创始人之一)在家中实现的远程监控和自动化。并在 OggCamp 的演讲上,对MQTT协议进行详细阐述。 ### 2.2 Mosquitto的安装 linux环境: centos 7 #### 2.2.1 安装工具 - yum install gcc gcc-c++ - yum install openssl-devel - yum install c-ares-devel - yum install libuuid-devel - yum install wget - yum install cmake - yum install build-essential python quilt devscripts python-setuptools python3 - yum install libssl-dev libc-ares-dev uuid-dev daemon openssl-devel #### 2.2.2 下载并编译安装libwebsockets - 下载:wget https://libwebsockets.org/git/libwebsockets/snapshot/libwebsockets-2.0.2.tar.gz - 解压:tar -zxvf libwebsockets-2.0.2.tar.gz - 进入相应的目录执行安装 - cd libwebsockets-2.0.2 - mkdir build - cd build - cmake .. -DLIB_SUFFIX=64 - make install - ldconfig #### 2.2.3 修正链接库 - vim /etc/ld.so.conf.d/liblocal.conf 输入内容 /usr/local/lib64 /usr/local/lib - ldconfig #### 2.2.4 下载并编译安装mosquitto - 下载:wget http://mosquitto.org/files/source/mosquitto-1.4.9.tar.gz - 解压:tar -xzvf mosquitto-1.4.9.tar.gz - cd mosquitto-1.4.9 - 增加WEBSOCKET支持 更改configure.mk中 WITH_WEBSOCKETS:=no 为 WITH_WEBSOCKETS:=yes - make - make install - 拷贝配置文件到指定地点:cp mosquitto.conf /etc/mosquitto #### 2.2.5 配置并启动mosquitto - 配置:在/etc/mosquitto/mosquitto.conf的Default Listener一节添加如下几行: pid_file /var/run/mosquitto.pid user root port 1883 max_connections -1 allow_anonymous true - 运行mosquitto mosquitto -c /etc/mosquitto/mosquitto.conf - 本机测试mosquitto A 订阅主题: mosquitto_sub -t topicA B 推送消息: mosquitto_pub -t topicA -h localhost -m "topicA test" ### 2.3 MQTTFX的安装和使用 MQTT.fx 是目前主流的mqtt客户端,可以快速验证是否可以与IoT Hub 服务交流发布或订阅消息。设备将当前所处的状态作为MQTT主题发送给IoT Hub,每个MQTT主题topic具有不同等级的名称,如“建筑/楼层/温度。” MQTT代理服务器将接收到的主题topic发送给给所有订阅的客户端。 #### 2.3.1 下载、安装和启动 下载地址:http://www.jensd.de/apps/mqttfx/1.5.0/ 启动后提示是否更新,选择否,否则会提示更新失败而退出 #### 2.3.2 配置 菜单栏 Extras -> Edit Connection Profiles 页面进行配置 创建一个新的连接 - 设置Broker Address,服务提供的IP地址 - 设置Broker Port,服务连接IP - 设置Client ID,选择后面的Generate自动生成就好了,只需要保证此ID和其他的客户端之间不冲突就可以 - 设置User Credentials,填写允许登录的用户名和密码(如果不做权限验证,可以不用填写) - 设置SSL/TLS,填写SSL加密策略,如果不适用SSL,可以不填写 - 启用 Enable SSL/TLS - 选择Self signed certificates - CA File 选择生成的ca.crt文件 - Client Certificate File 选择生成的client.crt文件 - Client Key File 选择生成的client.key文件 - Client Key Password 生成client.key时使用的密码 - PEM Formatted勾选后保存 #### 2.3.3 使用 选择刚刚创建的配置,点击Connect按钮启动连接 此时Publish页签可以给指定的地址发布消息 Subscribe可以订阅指定主题的消息,支持使用#和+的通配符 ---- ## 3 Mosquitto的集群部署 待定 ---- ## 4 Mosquitto的账号和权限 为了保障通讯的安全,MQTT支持基于用户名和密码的身份认证,Mosquitto在实现MQTT规范的基础上,提供了身份注册和身份认证的相关配置 为了确保数据的安全,Mosquitto提供了基于主题的权限控制 ### 4.1 Mosquitto账号配置 - 修改配置文件:mosquitto.conf 设置如下配置: allow_anonymous false password_file /etc/mosquitto/pwfile.example - 注册用户名和密码 打开命令窗口 键入如下命令 mosquitto_passwd /etc/mosquitto/pwfile.example admin 参数 -c 会清空原先配置的所有用户名和密码 ### 4.2 Mosquitto主题访问权限 - 修改配置文件:mosquitto.conf 设置配置如下: acl_file /etc/mosquitto/aclfile.example - 配置主题权限: 配置方式: user 用户名 topic 权限 主题名 操作权限: "read", "write" or "readwrite",不填默认为readwrite 主题名: 支持通配符 # 和 + ----- ## 5 Mosquitto的TLS连接方式 ### 5.1 秘钥生成 - 1 创建CA秘钥 openssl genrsa -out ca.key 2048 生成文件 ca.key - 2 创建CA证书 openssl req -new -x509 -days 3650 -key ca.key -out ca.crt 生成 ca.crt 需要填写国家(CN),省(zhejiang),市(hangzhou),组织名(dilan),机构名(igdata), common name(生成服务器的IP地址,不要填计算机名)和邮箱,此处密码全部被设置为123456,后面不在描述 - 3 创建服务端秘钥 openssl genrsa -out server.key 2048 生成文件 server.key - 4 创建服务端证书签署请求 openssl req -out server.csr -key server.key -new 生成文件 server.csr - 5 使用本地的ca证书签署服务端证书 openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 36500 生成文件 server.crt - 6 生成客户端秘钥 openssl genrsa -out client.key 2048 生成文件 client.key - 7 创建客户端证书签署请求 openssl req -out client.csr -key client.key -new 生成文件 client.csr - 8 使用本地的ca证书签署客户端证书 openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 36500 生成文件 client.crt - 9 合并证书,生成keystore文件 openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name tomcat -CAfile ca.crt -caname root -chain 生成文件 client.p12 - 10 生成ca.crt的jks文件 使用JAVA_HOME/bin目录下的工具keytool keytool -importcert -alias CA -file ca.crt -keystore ca.jks 生成文件 ca.jks - 11 生成client的keystore文件 keytool -importkeystore -v -srckeystore client.p12 -srcstoretype pkcs12 -srcstorepass 123456 -destkeystore client.keystore -deststoretype jks -deststorepass 123456 生成文件 client.keystore 其中 ca.crt,server.crt和server.key 文件在服务端使用 ca.crt,client.crt, client.key, client.keystore, ca.jks 文件在服务端使用 ### 5.2 Mosquitto秘钥配置 - 修改配置文件:mosquitto.conf cafile /home/madiot/w/ssl/ca.crt certfile /home/madiot/w/ssl/server.crt keyfile /home/madiot/w/ssl/server.key port 8883 #TLS协议的推荐端口为8883 #tls_version #配置 tls协议版本,可以不做配置 ### 5.3 MQTTFX配置 MQTTFX需要做相应的配置,使用到文件:ca.crt,client.crt, client.key,详细参考[2.3.2 设置SSL/TLS] ----- ## 6 MQTT的JAVA客户端使用 MQTT的JAVA客户端使用fusesource.mqtt-client 对应的maven配置: <dependency> <groupId>org.fusesource.mqtt-client</groupId> <artifactId>mqtt-client</artifactId> <version>1.14</version> </dependency> ### 6.1 服务端示例 import org.fusesource.mqtt.client.FutureConnection; import org.fusesource.mqtt.client.MQTT; import org.fusesource.mqtt.client.QoS; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.net.URISyntaxException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Date; /** * @ClassName: EcarServer * @Description: MQTT服务端 * @author Yi.Wang2 * @date 2018/6/13 */ public class EcarxServer { // MQTT服务器地址,使用tls作为scheme, ssl也可以 private final static String CONNECTION_STRING = "tls://192.168.32.128:8883"; // 连接时不清空session,需要填写clientId private final static boolean CLEAN_START = false; // 低耗网络,但是又需要及时获取数据,心跳30s private final static short KEEP_ALIVE = 30; // 最大重连次数 private final static long RECONNECTION_ATTEMPT_MAX = 6; // 重连间隔时间 private final static long RECONNECTION_DELAY = 2000; // 消息最大缓冲 private final static int SEND_BUFFER_SIZE = 2 * 1024 * 1024;//发送最大缓冲为2M public static void main(String[] args) { MQTT mqtt = new MQTT(); try { //设置服务端的ip mqtt.setHost(CONNECTION_STRING); //设置客户端ID mqtt.setClientId("ecarx"); //连接前清空会话信息 mqtt.setCleanSession(CLEAN_START); //设置重新连接的次数 mqtt.setReconnectAttemptsMax(RECONNECTION_ATTEMPT_MAX); //设置重连的间隔时间 mqtt.setReconnectDelay(RECONNECTION_DELAY); //设置心跳时间 mqtt.setKeepAlive(KEEP_ALIVE); //设置缓冲的大小 mqtt.setSendBufferSize(SEND_BUFFER_SIZE); // 连接断开通知(遗嘱) mqtt.setWillMessage("ecarx disconnected"); mqtt.setWillRetain(true); mqtt.setWillTopic("disconnect/ECARX100000000002"); mqtt.setWillQos(QoS.AT_LEAST_ONCE); // 用户名和密码 mqtt.setPassword("ecarx"); mqtt.setUserName("ecarx"); // 设置TLS连接容器 mqtt.setSslContext(getSSLContext()); //创建连接 final FutureConnection connection = mqtt.futureConnection(); connection.connect(); // 做一个连接判断,只有连接成功才执行数据发送 while(!connection.isConnected()); int count = 0; while (true) { count++; //发送内容 String message = "{\"vin\":\"ECARX100000000002\",\"latitude\":30214518,\"longitude\":120200523,\"altitude\":200,\"speed\":2200,\"gnss_direction\":270,\"charging\":4,\"total_mileage\":9999999,\"remaining_mileage\":2000,\"soc\":1000,\"car_state\":4,\"online_state\":3,\"central_lock_state\":0,\"doors_state\":0,\"lights_state\":0,\"trunk_state\":0,\"ac_state\":1,\"shift_mode\":14,\"handbrake_state\":1,\"sample_time\":\"2018-03-14 16:03:23\",\"type\":1}"; // 定义主题 String topic = "vehicle/report/ECARX100000000002"; // 发送 connection.publish(topic, message.getBytes(), QoS.AT_MOST_ONCE, true); System.out.println("MQTTFutureServer.publish Message, Topic Title :" + topic + ", count:" + count + ", currentTime: " + new Date()); // 每10秒发送一条实时车况 Thread.sleep(10000); } } catch (Exception e) { e.printStackTrace(); } } // 定义SSLContext TLS连接容器 private static SSLContext getSSLContext() throws NoSuchAlgorithmException, KeyStoreException, IOException, UnrecoverableKeyException, CertificateException, KeyManagementException { // 注册连接方式TLS(SSL也可以) SSLContext ctx = SSLContext.getInstance("TLS"); // 创建密码 KeyStore ks = KeyStore.getInstance("JKS"); KeyStore cks = KeyStore.getInstance("JKS"); // 加载密码文件,由于java只支持jks文件和keystore文件,所以上面特地生成相应的文件提供使用 ks.load(EcarxServer.class.getResourceAsStream("/ca.jks"), "123456".toCharArray()); cks.load(EcarxServer.class.getResourceAsStream("/client.keystore"), "123456".toCharArray()); // 创建公钥工厂和秘钥管理工程 TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); tmf.init(ks); kmf.init(cks, "123456".toCharArray()); // 初始化TLS连接容器 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); return ctx; } } ### 6.2 客户端示例 import org.fusesource.mqtt.client.Future; import org.fusesource.mqtt.client.FutureConnection; import org.fusesource.mqtt.client.MQTT; import org.fusesource.mqtt.client.Message; import org.fusesource.mqtt.client.QoS; import org.fusesource.mqtt.client.Topic; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; /** * @ClassName: IGDataClient * @Description: TODO * @author Yi.Wang2 * @date 2018/6/13 */ public class IGDataClient { // MQTT服务器地址,使用tls作为scheme, ssl也可以 private final static String CONNECTION_STRING = "tls://192.168.32.128:8883"; // 连接时不清空session,需要填写clientId private final static boolean CLEAN_START = false; // 低耗网络,但是又需要及时获取数据,心跳30s private final static short KEEP_ALIVE = 30; // 最大重连次数 public final static long RECONNECTION_ATTEMPT_MAX = 6; // 重连间隔时间 public final static long RECONNECTION_DELAY = 2000; // 订阅主题 public static Topic[] topics = { new Topic("vehicle/report/ECARX100000000002", QoS.AT_LEAST_ONCE)}; //发送最大缓冲为2M public final static int SEND_BUFFER_SIZE = 2 * 1024 * 1024; public static void main(String[] args) { //创建MQTT对象 MQTT mqtt = new MQTT(); try { //设置mqtt broker的ip和端口 mqtt.setHost(CONNECTION_STRING); //连接前清空会话信息 mqtt.setCleanSession(CLEAN_START); //设置重新连接的次数 mqtt.setReconnectAttemptsMax(RECONNECTION_ATTEMPT_MAX); //设置重连的间隔时间 mqtt.setReconnectDelay(RECONNECTION_DELAY); //设置心跳时间 mqtt.setKeepAlive(KEEP_ALIVE); //设置缓冲的大小 mqtt.setSendBufferSize(SEND_BUFFER_SIZE); // 连接断开通知(遗嘱) mqtt.setWillMessage("igdata disconnected"); mqtt.setWillRetain(true); mqtt.setWillTopic("disconnect/igdata"); mqtt.setWillQos(QoS.AT_LEAST_ONCE); // 用户名和密码 mqtt.setUserName("admin"); mqtt.setPassword("admin"); // 设置TLS连接容器 mqtt.setSslContext(getSSLContext()); //获取mqtt的连接对象BlockingConnection final FutureConnection connection = mqtt.futureConnection(); connection.connect(); // 订阅主题 connection.subscribe(topics); while (true) { Future<Message> futrueMessage = connection.receive(); Message message = futrueMessage.await(); // 接收消息并打印 System.out.println("MQTTFutureClient.Receive Message, Topic Title :" + message.getTopic() + " context :" + String.valueOf(message.getPayloadBuffer())); } } catch (Exception e) { e.printStackTrace(); } } // 见服务端实现 private static SSLContext getSSLContext() throws NoSuchAlgorithmException, KeyStoreException, IOException, UnrecoverableKeyException, CertificateException, KeyManagementException { ... } } ---- ## 7 Mosquitto的性能测试
博客
312312312
07-14
398
博客
32132
07-14
294
博客
312321312
07-12
236
02-06
1582
博客
试试文章类型
01-05
576
12-15
350
12-15
749
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交