HslCommunication.MQTT.MqttHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of HslCommunication Show documentation
Show all versions of HslCommunication Show documentation
一个工业物联网的底层架构框架,专注于底层的技术通信及跨平台,跨语言通信功能,实现各种主流的PLC数据读写,实现modbus的各种协议读写等等
package HslCommunication.MQTT;
import HslCommunication.BasicFramework.SoftBasic;
import HslCommunication.Core.Security.AesCryptography;
import HslCommunication.Core.Security.RSACryptoServiceProvider;
import HslCommunication.Core.Types.OperateResult;
import HslCommunication.Core.Types.OperateResultExOne;
import HslCommunication.Core.Types.OperateResultExTwo;
import HslCommunication.Robot.FANUC.FanucInterfaceNet;
import HslCommunication.StringResources;
import HslCommunication.Utilities;
import java.util.ArrayList;
/**
* Mqtt协议的辅助类,提供了一些协议相关的基础方法,方便客户端和服务器端一起调用。
* The auxiliary class of the Mqtt protocol provides some protocol-related basic methods for the client and server to call together.
*/
public class MqttHelper {
// region Static Helper Method
/**
* 根据数据的总长度,计算出剩余的数据长度信息
* According to the total length of the data, calculate the remaining data length information
* @param length 数据的总长度
* @return 计算结果
*/
public static OperateResultExOne CalculateLengthToMqttLength(int length ) {
if (length > 268_435_455) return new OperateResultExOne(StringResources.Language.MQTTDataTooLong());
if (length < 128) return OperateResultExOne.CreateSuccessResult(new byte[]{(byte) length});
if (length < 128 * 128) {
byte[] buffer = new byte[2];
buffer[0] = (byte) (length % 128 + 0x80);
buffer[1] = (byte) (length / 128);
return OperateResultExOne.CreateSuccessResult(buffer);
}
if (length < 128 * 128 * 128) {
byte[] buffer = new byte[3];
buffer[0] = (byte) (length % 128 + 0x80);
buffer[1] = (byte) (length / 128 % 128 + 0x80);
buffer[2] = (byte) (length / 128 / 128);
return OperateResultExOne.CreateSuccessResult(buffer);
} else {
byte[] buffer = new byte[4];
buffer[0] = (byte) (length % 128 + 0x80);
buffer[1] = (byte) (length / 128 % 128 + 0x80);
buffer[2] = (byte) (length / 128 / 128 % 128 + 0x80);
buffer[3] = (byte) (length / 128 / 128 / 128);
return OperateResultExOne.CreateSuccessResult(buffer);
}
}
/**
* 将一个数据打包成一个mqtt协议的内容
* Pack a piece of data into a mqtt protocol
* @param control 控制码
* @param flags 标记
* @param variableHeader 可变头的字节内容
* @param payLoad 负载数据
* @return 带有是否成功的结果对象
*/
public static OperateResultExOne BuildMqttCommand( byte control, byte flags, byte[] variableHeader, byte[] payLoad ) {
return BuildMqttCommand(control, flags, variableHeader, payLoad, null);
}
/**
* 将一个数据打包成一个mqtt协议的内容
* Pack a piece of data into a mqtt protocol
* @param control 控制码
* @param flags 标记
* @param variableHeader 可变头的字节内容
* @param payLoad 负载数据
* @param aesCryptography AES的加密解密对象
* @return 带有是否成功的结果对象
*/
public static OperateResultExOne BuildMqttCommand( byte control, byte flags, byte[] variableHeader, byte[] payLoad, AesCryptography aesCryptography ){
if (variableHeader == null) variableHeader = new byte[0];
if (payLoad == null) payLoad = new byte[0];
control = (byte) (control << 4);
byte head = (byte) (control | flags);
return BuildMqttCommand(head, variableHeader, payLoad, aesCryptography);
}
/**
* 将一个数据打包成一个mqtt协议的内容
* Pack a piece of data into a mqtt protocol
* @param head 控制码
* @param variableHeader 可变头的字节内容
* @param payLoad 负载数据
* @param aesCryptography AES加密对象
* @return 带有是否成功的结果对象
*/
public static OperateResultExOne BuildMqttCommand( byte head, byte[] variableHeader, byte[] payLoad, AesCryptography aesCryptography ) {
if (variableHeader == null) variableHeader = new byte[0];
if (payLoad == null) payLoad = new byte[0];
if (aesCryptography != null) payLoad = aesCryptography.Encrypt(payLoad);
// 先计算长度
OperateResultExOne bufferLength = CalculateLengthToMqttLength(variableHeader.length + payLoad.length);
if (!bufferLength.IsSuccess) return bufferLength;
ArrayList ms = new ArrayList();
ms.add(head);
Utilities.ArrayListAddArray(ms, bufferLength.Content);
if (variableHeader.length > 0) Utilities.ArrayListAddArray(ms, variableHeader);
if (payLoad.length > 0) Utilities.ArrayListAddArray(ms, payLoad);
return OperateResultExOne.CreateSuccessResult(Utilities.getBytes(ms));
}
/**
* 将字符串打包成utf8编码,并且带有2个字节的表示长度的信息
* Pack the string into utf8 encoding, and with 2 bytes of length information
* @param message 文本消息
* @return 打包之后的信息
*/
public static byte[] BuildSegCommandByString( String message ) {
byte[] buffer = Utilities.IsStringNullOrEmpty(message) ? new byte[0] : Utilities.getBytes(message, "UTF-8");
byte[] result = new byte[buffer.length + 2];
System.arraycopy(buffer, 0, result, 2, buffer.length);
result[0] = (byte) (buffer.length / 256);
result[1] = (byte) (buffer.length % 256);
return result;
}
/**
* 从MQTT的缓存信息里,提取文本信息
* Extract text information from MQTT cache information
* @param buffer Mqtt的报文
* @param index 索引
* @return 值
*/
public static OperateResultExTwo ExtraMsgFromBytes( byte[] buffer, int index ) {
int indexTmp = index;
int length = (buffer[index] & 0xFF) * 256 + (buffer[index + 1] & 0xFF);
index = index + 2 + length;
return OperateResultExTwo.CreateSuccessResult(Utilities.getString(buffer, indexTmp + 2, length, "UTF-8"), index);
}
/**
* 从MQTT的缓存信息里,提取长度信息
* Extract length information from MQTT cache information
* @param buffer Mqtt的报文
* @param index 索引
* @return 值
*/
public static OperateResultExTwo ExtraIntFromBytes( byte[] buffer, int index ) {
int length = (buffer[index] & 0xFF) * 256 + (buffer[index + 1] & 0xFF);
index += 2;
return OperateResultExTwo.CreateSuccessResult(length, index);
}
/**
* 从MQTT的缓存信息里,提取长度信息
* Extract length information from MQTT cache information
* @param data 数据信息
* @return 值
*/
public static byte[] BuildIntBytes( int data ) {
return new byte[]{Utilities.getBytes(data)[1], Utilities.getBytes(data)[0]};
}
/**
* 创建MQTT连接服务器的报文信息
* Create MQTT connection server message information
* @param connectionOptions 连接配置
* @param protocol 协议的内容
* @return 返回是否成功的信息
*/
public static OperateResultExOne BuildConnectMqttCommand(MqttConnectionOptions connectionOptions, String protocol ){
return BuildConnectMqttCommand(connectionOptions, protocol, null);
}
/**
* 创建MQTT连接服务器的报文信息
* Create MQTT connection server message information
* @param connectionOptions 连接配置
* @param protocol 协议的内容
* @param rsa rsa加密对象
* @return 返回是否成功的信息
*/
public static OperateResultExOne BuildConnectMqttCommand(MqttConnectionOptions connectionOptions, String protocol, RSACryptoServiceProvider rsa ) {
ArrayList variableHeader = new ArrayList();
Utilities.ArrayListAddArray(variableHeader, new byte[]{0x00, 0x04});
Utilities.ArrayListAddArray(variableHeader, Utilities.getBytes(protocol, "US-ASCII")); // 协议版本,3.1.1
variableHeader.add((byte) 0x04);
byte connectFlags = 0x00;
if (connectionOptions.Credentials != null) // 是否需要验证用户名和密码
{
connectFlags = (byte) (connectFlags | 0x80);
connectFlags = (byte) (connectFlags | 0x40);
}
if (connectionOptions.CleanSession) {
connectFlags = (byte) (connectFlags | 0x02);
}
variableHeader.add(connectFlags);
if (connectionOptions.KeepAlivePeriod < 1) connectionOptions.KeepAlivePeriod = 1;
byte[] keepAlivePeriod = Utilities.getBytes(connectionOptions.KeepAlivePeriod);
variableHeader.add(keepAlivePeriod[1]);
variableHeader.add(keepAlivePeriod[0]);
ArrayList payLoad = new ArrayList();
Utilities.ArrayListAddArray(payLoad, BuildSegCommandByString(connectionOptions.ClientId)); // 添加客户端的id信息
if (connectionOptions.Credentials != null) // 根据需要选择是否添加用户名和密码
{
Utilities.ArrayListAddArray(payLoad, BuildSegCommandByString(connectionOptions.Credentials.getUserName()));
Utilities.ArrayListAddArray(payLoad, BuildSegCommandByString(connectionOptions.Credentials.getPassword()));
}
if (rsa == null)
return BuildMqttCommand(MqttControlMessage.CONNECT, (byte) 0x00, Utilities.getBytes(variableHeader), Utilities.getBytes(payLoad));
else
return BuildMqttCommand(MqttControlMessage.CONNECT, (byte) 0x00,
rsa.EncryptLargeData(Utilities.getBytes(variableHeader)),
rsa.EncryptLargeData(Utilities.getBytes(payLoad)));
}
/**
* 根据服务器返回的信息判断当前的连接是否是可用的
* According to the information returned by the server to determine whether the current connection is available
* @param code 功能码
* @param data 数据内容
* @return 是否可用的连接
*/
public static OperateResult CheckConnectBack(byte code, byte[] data ) {
if (code >> 4 != MqttControlMessage.CONNACK) return new OperateResult("MQTT Connection Back Is Wrong: " + code);
if (data.length < 2)
return new OperateResult("MQTT Connection Data Is Short: " + SoftBasic.ByteToHexString(data, ' '));
int status = (data[0] & 0xFF) * 256 + (data[1] & 0xFF);
if (status > 0) return new OperateResult(status, GetMqttCodeText(status));
return OperateResult.CreateSuccessResult();
}
/**
* 获取当前的错误的描述信息
* Get a description of the current error
* @param status 状态信息
* @return 描述信息
*/
public static String GetMqttCodeText( int status ) {
switch (status) {
case 1:
return StringResources.Language.MQTTStatus01();
case 2:
return StringResources.Language.MQTTStatus02();
case 3:
return StringResources.Language.MQTTStatus03();
case 4:
return StringResources.Language.MQTTStatus04();
case 5:
return StringResources.Language.MQTTStatus05();
default:
return StringResources.Language.UnknownError();
}
}
/**
* 创建Mqtt发送消息的命令
* Create Mqtt command to send messages
* @param message 封装后的消息内容
* @return 结果内容
*/
public static OperateResultExOne BuildPublishMqttCommand( MqttPublishMessage message ) {
byte flag = 0x00;
if (!message.IsSendFirstTime) flag = (byte) (flag | 0x08);
if (message.Message.Retain) flag = (byte) (flag | 0x01);
if (message.Message.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce) flag = (byte) (flag | 0x02);
else if (message.Message.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
flag = (byte) (flag | 0x04);
else if (message.Message.QualityOfServiceLevel == MqttQualityOfServiceLevel.OnlyTransfer)
flag = (byte) (flag | 0x06);
ArrayList variableHeader = new ArrayList();
Utilities.ArrayListAddArray(variableHeader, BuildSegCommandByString(message.Message.Topic));
if (message.Message.QualityOfServiceLevel != MqttQualityOfServiceLevel.AtMostOnce) {
variableHeader.add(Utilities.getBytes(message.Identifier)[1]);
variableHeader.add(Utilities.getBytes(message.Identifier)[0]);
}
return BuildMqttCommand(MqttControlMessage.PUBLISH, flag, Utilities.getBytes(variableHeader), message.Message.Payload);
}
/**
* 创建Mqtt发送消息的命令
* Create Mqtt command to send messages
* @param topic 主题消息内容
* @param payload 数据负载
* @return 结果内容
*/
public static OperateResultExOne BuildPublishMqttCommand( String topic, byte[] payload ) {
return BuildMqttCommand(MqttControlMessage.PUBLISH, (byte) 0x00, BuildSegCommandByString(topic), payload);
}
/**
* 创建MQTT订阅消息的命名
* Command to create Mqtt subscription message
* @param message 订阅的主题
* @return 结果内容
*/
public static OperateResultExOne BuildSubscribeMqttCommand( MqttSubscribeMessage message ) {
ArrayList variableHeader = new ArrayList();
ArrayList payLoad = new ArrayList();
variableHeader.add(Utilities.getBytes(message.Identifier)[1]);
variableHeader.add(Utilities.getBytes(message.Identifier)[0]);
for (int i = 0; i < message.Topics.length; i++) {
Utilities.ArrayListAddArray(payLoad, BuildSegCommandByString(message.Topics[i]));
if (message.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
payLoad.add((byte) 0x00);
else if (message.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
payLoad.add((byte) 0x01);
else
payLoad.add((byte) 0x02);
}
return BuildMqttCommand(MqttControlMessage.SUBSCRIBE, (byte) 0x02, Utilities.getBytes(variableHeader), Utilities.getBytes(payLoad));
}
/**
* 创建Mqtt取消订阅消息的命令
* Create Mqtt unsubscribe message command
* @param message 订阅的主题
* @return 结果内容
*/
public static OperateResultExOne BuildUnSubscribeMqttCommand( MqttSubscribeMessage message ) {
ArrayList variableHeader = new ArrayList();
ArrayList payLoad = new ArrayList();
variableHeader.add(Utilities.getBytes(message.Identifier)[1]);
variableHeader.add(Utilities.getBytes(message.Identifier)[0]);
for (int i = 0; i < message.Topics.length; i++) {
Utilities.ArrayListAddArray(payLoad, BuildSegCommandByString(message.Topics[i]));
}
return BuildMqttCommand(MqttControlMessage.UNSUBSCRIBE, (byte) 0x02, Utilities.getBytes(variableHeader), Utilities.getBytes(payLoad));
}
/**
* 解析从MQTT接受的客户端信息,解析成实际的Topic数据及Payload数据
* Parse the client information received from MQTT and parse it into actual Topic data and Payload data
* @param mqttCode MQTT的命令码
* @param data 接收的MQTT原始的消息内容
* @return 解析的数据结果信息
*/
public static OperateResultExTwo ExtraMqttReceiveData(byte mqttCode, byte[] data ) {
return ExtraMqttReceiveData(mqttCode, data, null);
}
/**
* 解析从MQTT接受的客户端信息,解析成实际的Topic数据及Payload数据
* Parse the client information received from MQTT and parse it into actual Topic data and Payload data
* @param mqttCode MQTT的命令码
* @param data 接收的MQTT原始的消息内容
* @param aesCryptography AES加密解密的对象
* @return 解析的数据结果信息
*/
public static OperateResultExTwo ExtraMqttReceiveData(byte mqttCode, byte[] data, AesCryptography aesCryptography ){
if (data.length < 2)
return new OperateResultExTwo(StringResources.Language.ReceiveDataLengthTooShort() + data.length);
int topicLength = (data[0] & 0xFF) * 256 + (data[1] & 0xFF);
if (data.length < 2 + topicLength)
return new OperateResultExTwo("Code[" + mqttCode + "] Subscribe Error: " + SoftBasic.ByteToHexString(data, ' '));
String topic = topicLength > 0 ? Utilities.getString(data, 2, topicLength, "UTF-8") : "";
byte[] payload = new byte[data.length - topicLength - 2];
System.arraycopy(data, topicLength + 2, payload, 0, payload.length);
if(aesCryptography != null){
try{
payload = aesCryptography.Decrypt(payload);
}
catch (Exception ex){
return new OperateResultExTwo<>( "AES Decrypt failed: " + ex.getMessage() );
}
}
return OperateResultExTwo.CreateSuccessResult(topic, payload);
}
// endregion
}