mqtt
package pro.nbbt.xulian.business.wireless.map.config;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.stereotype.Component;
import pro.nbbt.xulian.business.common.util.mqtt.wireless.WirelessMqttClientWorker;
import javax.annotation.PostConstruct;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
@Data
@Slf4j
@Component
@IntegrationComponentScan
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "nbbt.wireless.mqtt")
public class WirelessMqttClientPool {
private static final int POOL_SIZE = 4; // Adjust the pool size as needed
private static final BlockingQueue<WirelessMqttClientWorker> pool = new LinkedBlockingQueue<>(POOL_SIZE);
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 连接地址
*/
private String hostUrl;
/**
* 客户Id
*/
private String clientId;
/**
* 监听 topic
*/
private String listenTopics;
/**
* 超时时间
*/
private int timeout;
/**
* 保持连接数
*/
private int keepalive;
/**
* 设备在线超时时间,默认10分钟,超过10分钟设备无新消息,则主动设置为离线
*/
private Integer expireSeconds;
/**
* 是否保存509日志
*/
private boolean savelog;
/**
* 设备状态延迟更新到数据,单位毫秒
*/
private int statusdelayupdatemillseconds;
private MqttConnectOptions mqttConnectOptions;
public WirelessMqttClientPool() {
}
@PostConstruct
private void initializePool() {
if (mqttConnectOptions == null) {
mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setUserName(username);
mqttConnectOptions.setPassword(password.toCharArray());
mqttConnectOptions.setServerURIs(new String[]{hostUrl});
mqttConnectOptions.setMaxInflight(100000000);
mqttConnectOptions.setConnectionTimeout(30 * 1000);//连接超时时间
log.debug("初始化mqttConnectOptions完成:{}", username);
}
try {
for (int i = 0; i < POOL_SIZE; i++) {
WirelessMqttClientWorker mqttClient = createMqttClientWorker();
pool.offer(mqttClient);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private WirelessMqttClientWorker createMqttClientWorker() throws MqttException {
// You may need to modify this method based on your requirements
// For example, you may want to customize host, clientId, options, etc.
log.debug("打印出url======================:{}", hostUrl);
return new WirelessMqttClientWorker(hostUrl, clientId + MqttAsyncClient.generateClientId(), mqttConnectOptions,
"defaultTopic", null);
}
public WirelessMqttClientWorker acquireConnection() {
try {
WirelessMqttClientWorker mqttClient = pool.take();
if (!mqttClient.isConnected()) {
// If the connection is lost, reconnect
mqttClient.reconnect();
}
return mqttClient;
} catch (InterruptedException e) {
log.error("获取连接中断异常");
return null;
}
}
public void releaseConnection(WirelessMqttClientWorker mqttClient) {
if (mqttClient != null) {
pool.offer(mqttClient);
}
}
}
package pro.nbbt.xulian.business.common.util.mqtt.wireless;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import pro.nbbt.xulian.business.common.util.mqtt.MqttMessageRecieverInterface;
import pro.nbbt.xulian.common.util.redission.RedissionUtils;
import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@Slf4j
public class WirelessMqttClientWorker {
private String host;
private String clientId;
private MqttConnectOptions options;
private String subscribeTopic;
private MqttMessageRecieverInterface msgCallback;
private MqttClient client;
private final int DEFAULT_TOPIC_QOS = 1;
private final String DEFAULT_TEXT_CODE = "UTF-8";
private final Integer timeToWait = 1000;
@Resource
RedissionUtils redissionUtils;
private static final AtomicInteger idWorker = new AtomicInteger(0);
public WirelessMqttClientWorker(String host, String clientId, MqttConnectOptions options, String subscribeTopic, MqttMessageRecieverInterface msgCallback) throws MqttException {
this.host = host;
this.clientId = clientId;
this.options = options;
this.subscribeTopic = subscribeTopic;
this.msgCallback = msgCallback;
log.info(String.format("wireless connet param : %s : %s", this.host, this.clientId));
this.client = new MqttClient(this.host, this.clientId, new MemoryPersistence());
this.client.setCallback(new MqttCallbackImpl());
this.client.setTimeToWait(this.timeToWait); // 增加pushlish的时间限制,防止发生堵塞
this.client.connect(this.options);
log.info(String.format("wireless client param : %s ", client));
if (StrUtil.isNotBlank(subscribeTopic)) {
String[] topics = StrUtil.split(this.subscribeTopic, ',').stream()
.map(String::trim)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toList())
.toArray(new String[]{});
if (topics.length > 0) {
this.client.subscribe(topics);
}
}
log.info("wireless MQTT CLIENT({}) 正在连接", clientId);
}
public void close() {
redissionUtils.setConcurrentLock(clientId);
try {
this.client.close();
} catch (MqttException e) {
e.printStackTrace();
} finally {
redissionUtils.deleteConcurrentLock(clientId);
}
}
public boolean isConnected() {
return this.client.isConnected();
}
public void publish(String topic, byte[] bytes) {
this.publish(topic, bytes, DEFAULT_TOPIC_QOS);
}
public void publish(String topic, byte[] bytes, int qos) {
/* redissionUtils.setConcurrentLock(topic);
try {*/
MqttMessage msg = new MqttMessage(bytes);
msg.setQos(qos);
if (idWorker.get() >= Integer.MAX_VALUE) {
idWorker.set(0);
}
msg.setId(idWorker.getAndIncrement());
try {
this.client.publish(topic, msg);
log.debug("MQTT CLIENT({}) ==={}===> {}", clientId, topic, Message2String(msg));
} catch (MqttException e) {
log.warn("MQTT CLIENT({}) 在发送消息时发生错误 {},{},{}", clientId, e.getMessage(), topic, Message2String(msg));
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
/*} finally {
redissionUtils.deleteConcurrentLock(topic);
}*/
}
public void publish(String topic, String text) {
try {
this.publish(topic, text.getBytes(DEFAULT_TEXT_CODE), 0);
} catch (UnsupportedEncodingException e) {
log.warn("MQTT CLIENT({}) 在发送消息时发生转换错误 {},{},{}", clientId, e.getMessage(), topic, text);
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
public void publish(String topic, String text, int qos) {
try {
// this.publish(topic, text.getBytes(DEFAULT_TEXT_CODE),2);
// test 临时改为1,验证fluxMQ无法释放堆内存的问题 记得改回
this.publish(topic, text.getBytes(DEFAULT_TEXT_CODE), qos);
} catch (UnsupportedEncodingException e) {
log.warn("MQTT CLIENT({}) 在发送消息时发生转换错误 {},{},{}", clientId, e.getMessage(), topic, text);
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
private final class MqttCallbackImpl implements MqttCallback {
@Override
public void connectionLost(Throwable cause) {
log.error("MQTT CLIENT({}) 丢失连接", clientId);
if (!client.isConnected()) {
redissionUtils.setConcurrentLock(clientId);
try {
client.reconnect();
log.info("MQTT CLIENT({}) 正在连接(重连)", clientId);
} catch (Exception e) {
log.error("MQTT CLIENT({}) 重连发生错误 {}", clientId, e.getMessage());
e.printStackTrace();
} finally {
redissionUtils.deleteConcurrentLock(clientId);
}
}
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
log.debug("MQTT CLIENT({}) <==={}=== {}", clientId, topic, Message2String(message));
if (null != msgCallback) {
try {
msgCallback.onMessage(topic, message);
} catch (Exception ex) {
log.warn("MQTT CLIENT({}) 在处理消息时发生错误 {},{},{}", clientId, ex.getMessage(), topic, Message2String(message));
ex.printStackTrace();
}
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// log.debug("MQTT CLIENT({}) Delivery Complete {}",clientId,token);
}
}
public void reconnect() {
try {
log.debug("打印出mqttClient进行重连======================:{}");
client.reconnect();
} catch (Exception e) {
log.error("MQTT CLIENT({}) 重连发生错误 {}", clientId, e.getMessage());
e.printStackTrace();
}
}
private String Message2String(MqttMessage message) {
return "【message:id=" + message.getId() +
",qos=" + message.getQos() +
",dup=" + message.isDuplicate() +
",retain=" + message.isRetained() +
",qos=" + message.getQos() +
",data=" + HexUtil.encodeHexStr(message.getPayload(), false)
+ "】";
}
}
try {
log.info("------------------------------------给基站发送的topic是:" + STATION + StrUtil.SLASH + deviceSn + TOPIC + CMD + "发送的内容是:" + content);
mqttClientWorker.publish(STATION + StrUtil.SLASH + deviceSn + TOPIC + CMD, content);
sendStationDeviceLogs(deviceSn, content);
} catch (Exception e) {
log.error("给基站发送消息失败,发送的topic是:" + STATION + StrUtil.SLASH + deviceSn + TOPIC + CMD + "发送的内容是:" + content, e);
} finally {
bean.releaseConnection(mqttClientWorker);
}
浙公网安备 33010602011771号