MQTT安装部署手册

-----
## 目录
*	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是一个客户端服务端架构的发布/订阅模式的消息传输协议。它的设计思想是轻巧、开放、简单、规范,易于实现。这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器的通信(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)用于分割主题的每个层级,为主题名提供一个分层结构。当客户端订阅指定的主题过滤器包含两种通配符时,主题层级分隔符就很有用了。主题层级分隔符可以出现在主题过滤器或主题名字的任何位置。相邻的主题层次分隔符表示一个零长度的主题层级。

- 多层通配符—“#”  
“#”是用于匹配主题中任意层级的通配符。多层通配符表示它的父级和任意数量的子层级。多层通配符必须位于它自己的层级或者跟在主题层级分隔符后面。不管哪种情况,它都必须是主题过滤器的最后一个字符。

- 单层通配符—“+”  
加号是只能用于单个主题层级匹配的通配符。在主题过滤器的任意层级都可以使用单层通配符,包括第一个和最后一个层级。然而它必须占据过滤器的整个层级 。可以在主题过滤器中的多个层级中使用它,也可以和多层通配符一起使用。

- 系统消息通配符 —“$”  
常见于“$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节。

注意:retain关键字设置为true时,当设置QoS > 0的场景,后发的消息将不被保存,当设置QoS = 0的场景,后发的消息将替换之前的消息。
MQTT不支持消息存储,针对每一个通道,只保留最多一条消息,如果错过了消费,就会被丢弃,所以消费者不能被关闭,否则消息将发生丢失


**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配置:
	
		
            org.fusesource.mqtt-client
            mqtt-client
            1.14
        

### 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 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的性能测试
Categories: Plus

发表评论 取消回复

MQTT安装部署手册_第1张图片

电子邮件地址不会被公开。

Name
Email
Website
What's on your mind?

近期文章
  • Maven deploy部署jar到远程私服仓库
  • java动态代理实现与原理
  • git 常用命令
  • java中观察者模式Observable和Observer
  • Netty解决TCP粘包和拆包问题的四种方案
近期评论
  • 马化腾发表在《Nginx的一些基本功能》
  • geyang发表在《世界,您好!》
  • 一位WordPress评论者发表在《世界,您好!》
分类目录
  • Big Data (5)
  • Java (27)
  • MicroServices (13)
    • GateWay (2)
    • REST (2)
  • Plus (38)
  • Spring (9)
    • Spring Boot (5)
    • Spring Data (4)
  • 中间件/框架 (5)
    • Kafka (3)
  • 数据库 (11)
    • Hbase (5)
    • MongoDb (2)
    • Mysql (3)
标签
apiDoc Drools dubbo fiddler Grafana hbase Hystrix IDEA java JDK jpa jvisualvm jvm kafka linux MongoDB MQTT Mysql Netty nginx OpenJDK Prometheus REST RocketMQ RPC Servlet Sleuth SOA spring boot spring data zookeeper Zuul 域名 微服务 数据结构 日志 爬虫 缓存 股票 设计模式 读书 运维 队列 集合 音乐
联系我

你可能感兴趣的:(MQTT安装部署手册)