EMQTT使用随笔
服务器配置与准备工作
由于emqttd是用Erlang语言编写的,所以,在Linux下安装时,需要先安装Erlang。
安装-配置命令如下:
一、安装依赖库
sudo yum -y install make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel
二、获取源码包
wget http://www.erlang.org/download/otp_src_R13B04.tar.gz
三、解压、编译、安装
tar xfvz otp_src_R13B04.tar.gz
cd otp_src_R13B04/
./configure --with-ssl
sudo make install
此时配置EMQTT的环境已搭建好
部署EMQTT
一、下载EMQTT安装包
【各版本下载地址:https://www.emqx.io/downloads/broker/?osType=Linux,我所使用的是3.2.3版】
由于服务器是Linux所以下载的Linux通用安装包:
https://www.emqx.io/downloads/broker/v3.2.3/emqx-centos6-v3.2.3.zip
然后将下载的zip文件解压,并放到服务器下【我的:opt/emqx】
二、调用命令启动EMQTT
cd /opt/emqx/bin
./emqx console
提示若没有权限,逐级获取权限【命令 chmod u+x * 我是获取了三次不同目录的权限】
直到调用 ./emqx console 命令有以下提示
Ctrl + C 退出 并调用 ./emqx start 启动 MQTT服务 有以下提示标识启动成功
ps -ef|grep emqx 可以查看当前的 emqtt服务
登录WEB 管理后台—配置MQTT服务参数
地址: http://localhost:18083
,缺省用户名/密码: admin/public
。
设置语言为中文
设置用户名 与 密码【重要】
编码实现[java]
导入依赖
<dependencies>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
/**
* MQTT静态参数常量类
*/
public class MqttConstant {
//MQTT 服务器基础配置
/**
* MQTT服务器IP、端口
*/
public final static String MQTT_IP_PORT = "tcp://test:1883";
/**
* MQTT服务器登录 用户名 elinker
*/
public final static String MQTT_USERNAME = "username";
/**
* MQTT服务器登录 密码
*/
public final static String MQTT_PASSWORD = "password";
/**
* MQTT客户端【应用程序】 ID【自定义】
*/
public final static String MQTT_CLIENTID = "pubClient";
/**
* MQTT客户端【应用程序】 订阅主题【自定义】
*/
public final static String MQTT_TOPIC = "web/pubClient";
//消息发送的类型
/**
* 尽力而为。消息发送者会想尽办法发送消息,但是遇到意外并不会重试
*/
public final static int QOS_UNRELIABLE = 0;
/**
* 至少一次。消息接收者如果没有知会或者知会本身丢失,消息发送者会再次发送以保证消息接收者至少会收到一次,当然可能造成重复消息。
*/
public final static int QOS_REPEAT = 1;
/**
* 恰好一次。保证这种语义肯待会减少并发或者增加延时,不过丢失或者重复消息是不可接受的时候,级别2是最合适的。
*/
public final static int QOS_JUST = 2;
}
/**
* 服务器【应用程序】Mqtt消息推送工具类
*/
public class MqttPushUtil {
public static Logger logger = Logger.getLogger(MqttPushUtil.class);
public static MqttClient mqttClient;
public static MqttConnectOptions mqttConnectOptions;
static {
try{
//创建客户端
mqttClient = new MqttClient(MqttConstant.MQTT_IP_PORT, MqttConstant.MQTT_CLIENTID, new MemoryPersistence());
//创建链接参数
mqttConnectOptions = new MqttConnectOptions();
//在客户端断开连接时是否缓存 订阅消息
mqttConnectOptions.setCleanSession(true);
//设置连接的用户名
mqttConnectOptions.setUserName(MqttConstant.MQTT_USERNAME);
//设置连接的密码
mqttConnectOptions.setPassword(MqttConstant.MQTT_PASSWORD.toCharArray());
//开启自动重连
mqttConnectOptions.setAutomaticReconnect(true);
//设置超时时间 单位为秒
mqttConnectOptions.setConnectionTimeout(30);
//设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
mqttConnectOptions.setKeepAliveInterval(20);
// MqttPushServerUtil.setClient(mqttClient);
mqttClient.connect(mqttConnectOptions);
}catch (Exception e){
e.printStackTrace();
logger.error("连接MQTT服务器发生异常", e);
try{
mqttClient.disconnect();;
mqttClient.close();
}catch (MqttException el){
e.printStackTrace();
logger.error("连接异常时-----》断开与MQTT服务器连接操作发生异常", el);
}
}
}
public static void receiveSubscription(){
try{
mqttClient.setCallback(new MqttCallback() {
/**
*检测到断开连接
* @param throwable
*/
@Override
public void connectionLost(Throwable throwable) {
//MQTT客户端断线重连
reconnection();
}
/**
* 接收订阅消息处理
* @param topic
* @param mqttMessage
* @throws Exception
*/
@Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
System.out.println("topic:"+topic);
System.out.println("Qos:"+mqttMessage.getQos());
System.out.println("message content:"+new String(mqttMessage.getPayload()));
}
/**
* 消息发布结果
* @param iMqttDeliveryToken
*/
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
logger.info("MQTT消息发布的结果:---------"+ iMqttDeliveryToken.isComplete());
}
});
mqttClient.subscribe(MqttConstant.MQTT_TOPIC, MqttConstant.QOS_JUST);
}catch (Exception e){
e.printStackTrace();
logger.error("MQTT客户端---公租房系统:接收消息时发生异常!", e);
}
}
/**
* MQTT客户端断线重连
*/
public static void reconnection(){
logger.error("与MQTT服务器断开连接,尝试重新连接!");
try {
if(!mqttConnectOptions.isAutomaticReconnect()){
mqttClient.reconnect();
}
}catch (MqttException e){
logger.error("MQTT重新连接发生异常!", e);
}
}
/**
* 发布非可靠的消息【消息服务质量:0】
* @param topic 发布主题
* @param pushMessage 消息内容
*/
public static boolean publishUnreliable(String topic, String pushMessage) {
return publish(MqttConstant.QOS_UNRELIABLE, topic, pushMessage);
}
/**
* 以至少收到一次的模式发送消息【可能重复,消息服务质量:1】
* @param topic 发布主题
* @param pushMessage 消息内容
*/
public static boolean publishLeastOnce(String topic, String pushMessage) {
return publish(MqttConstant.QOS_REPEAT, topic, pushMessage);
}
/**
* 发送可靠的保证 能且只能收到一次的消息【消息服务质量:2】
* @param topic
* @param pushMessage
*/
public static boolean publishReliable(String topic, String pushMessage) {
return publish(MqttConstant.QOS_JUST, topic, pushMessage);
}
/**
* 发布主题和消息队列
* @param qos
* @param topic
* @param pushMessage
* @return
*/
public static boolean publish(int qos, String topic, String pushMessage) {
try {
// 创建消息
MqttMessage message = new MqttMessage(pushMessage.getBytes());
// 设置消息的服务质量
message.setQos(qos);
// 发布消息
mqttClient.publish(topic, message);
} catch (MqttException e) {
logger.error("发布消息时发生异常!",e);
return false;
}
return true;
}
}
/**
* 测试类
*/
public class MqttPushClientUtil {
public static void main(String[] args) throws MqttException {
String HOST = MqttConstant.MQTT_IP_PORT;
String[] TOPIC = {"dev/mac/0000a4010101", "dev/village/123"};
int[] qos = new int[]{2, 2};
String clientid = "subClient";
String userName = "username";
String passWord = "password";
try {
// host为主机名,subClient为clientid即连接MQTT的客户端ID,一般以客户端唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
MqttClient client = new MqttClient(HOST, clientid, new MemoryPersistence());
// MQTT的连接设置
MqttConnectOptions options = new MqttConnectOptions();
// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
options.setCleanSession(true);
// 设置连接的用户名
options.setUserName(userName);
// 设置连接的密码
options.setPassword(passWord.toCharArray());
// 设置超时时间 单位为秒
options.setConnectionTimeout(10);
// 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
options.setKeepAliveInterval(20);
// 设置回调函数
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
System.out.println("connectionLost");
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
System.out.println("topic:"+topic);
System.out.println("Qos:"+message.getQos());
System.out.println("message content:"+new String(message.getPayload()));
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
System.out.println("deliveryComplete---------"+ token.isComplete());
}
});
client.connect(options);
//订阅消息
client.subscribe(TOPIC, qos);
} catch (Exception e) {
e.printStackTrace();
}
Map<String, Object> map = new HashMap<>();
map.put("index", 1);
map.put("text", "设备信息");
MqqtPushServiceUtil.pushDeviceMsg("00:00:a4:01:01:01", "12", map);
try{
Thread.sleep(5000);
}catch (Exception e){
e.printStackTrace();
}
map.put("index", 2);
map.put("text", "小区信息");
MqqtPushServiceUtil.pushVillageMsg(123, "12", map);
}
}
import com.alibaba.fastjson.JSONObject;
import com.framework.common.mqtt.MqttPushUtil;
import com.framework.common.utils.StringUtil;
import java.util.HashMap;
import java.util.Map;
/**
* MQTT消息推送业务工具类
*/
public class MqttPushServiceUtil {
//
//主要用来参考 具体规则与接受端约定
//MqttPushConstant.VILLAGE_PUSH_TOPIC+villageId 指约定订阅的标题 map.toString() json格式的字符串
/*---------------------------------------------------------------------------------------------------------------------------------------*/
/**
* 推送设备消息
* @param mac
* @param type
* @return
*/
public static boolean pushDeviceMsg(String mac, String type){
if(StringUtil.isBlank(mac)){
return false;
}
Map<String, Object> map = new JSONObject();
map.put("type", type);
return MqttPushUtil.publishLeastOnce(MqttPushConstant.DEVICE_PUSH_TOPIC+mac.replace(":", ""), map.toString());
}
/**
* 推送设备消息
* @param mac 设备mac
* @param type 消息类型【自定义】
* @param pubshMsg 消息内容
* @return
*/
public static boolean pushDeviceMsg(String mac, String type, Map<String, Object> pubshMsg){
if(StringUtil.isBlank(mac)){
return false;
}
Map<String, Object> map = new JSONObject();
map.put("type", type);
map.put("msg", new JSONObject(pubshMsg).toJSONString());
return MqttPushUtil.publishReliable(MqttPushConstant.DEVICE_PUSH_TOPIC+mac.replace(":", ""), map.toString());
}
/**
* 推送小区消息
* @param villageId 小区ID
* @param type 消息类型【自定义】
* @param pubshMsg 消息内容
* @return
*/
public static boolean pushVillageMsg(int villageId, String type, Map<String, Object> pubshMsg){
if(villageId <= 0){
return false;
}
Map<String, Object> map = new JSONObject();
map.put("type", type);
map.put("msg", new JSONObject(pubshMsg).toJSONString());
return MqttPushUtil.publishReliable(MqttPushConstant.VILLAGE_PUSH_TOPIC+villageId, map.toString());
}
}