2.我用的Unity3d 2021.3.35,对应的 .NET Framework 版本是 4.8,需要将lib/net48下的MQTTnet.dll放到Assets/Plugins下

3.Project Settings一般不用改

4.代码
MqttMgr.cs,支持自动重连
cs
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
public class MqttMgr : MonoBehaviour
{
public static MqttMgr Instance { get; private set; }
[Header("MQTT 配置")]
public string broker = "broker.hivemq.com";
public int port = 1883;
public string clientIdPrefix = "UnityClient_";
public string username = "";
public string password = "";
[Header("自动重连")]
public int reconnectInterval = 3000;
public event Action OnConnected;
public event Action<string> OnDisconnected;
public event Action<string, string> OnMessageReceived;
public event Action<string> OnLog;
// 【新增】MQTT连接状态属性,外部直接调用:MqttMgr.Instance.isMqttConnected
public bool isMqttConnected => _mqttClient != null && _mqttClient.IsConnected;
/// <summary>
/// 是否已初始化
/// </summary>
public static bool IsInitialized => Instance != null;
private IMqttClient _mqttClient;
private CancellationTokenSource _cts;
private string _clientId;
private bool _isConnecting;
private bool _manualDisconnect;
private const string MQTT_TOPIC = "yiyue/lanyi";
private const string MQTT_PUBLISH = "lanyi/yiyue";
public string MqttTopic => MQTT_TOPIC;
private void Awake()
{
if (Instance != null) { Destroy(gameObject); return; }
Instance = this;
DontDestroyOnLoad(gameObject);
_clientId = clientIdPrefix + Guid.NewGuid().ToString("N").Substring(0, 8);
}
public async Task ConnectAsync()
{
if (_isConnecting) return;
try
{
_manualDisconnect = false;
_isConnecting = true;
if (_cts != null)
{
_cts.Cancel();
_cts.Dispose();
}
_cts = new CancellationTokenSource();
if (_mqttClient != null)
{
_mqttClient.ConnectedAsync -= OnClientConnected;
_mqttClient.DisconnectedAsync -= OnClientDisconnected;
_mqttClient.ApplicationMessageReceivedAsync -= OnApplicationMessageReceived;
_mqttClient.Dispose();
_mqttClient = null;
}
var factory = new MqttFactory();
_mqttClient = factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithTcpServer(broker, port)
.WithClientId(_clientId)
.WithCleanSession()
.WithKeepAlivePeriod(TimeSpan.FromSeconds(10))
.Build();
_mqttClient.ConnectedAsync += OnClientConnected;
_mqttClient.DisconnectedAsync += OnClientDisconnected;
_mqttClient.ApplicationMessageReceivedAsync += OnApplicationMessageReceived;
// 5秒超时保护,防止断网卡死
var connectTask = _mqttClient.ConnectAsync(options, _cts.Token);
var timeoutTask = Task.Delay(5000, _cts.Token);
await Task.WhenAny(connectTask, timeoutTask);
if (!connectTask.IsCompletedSuccessfully)
{
_cts.Cancel();
Log("连接超时,继续重试...");
}
}
catch (Exception ex)
{
Log($"连接异常:{ex.Message}");
}
finally
{
_isConnecting = false;
// 失败就继续重连 → 无限循环
if (!_manualDisconnect && PubMethod.ReconnectLanYiMgr && (_mqttClient == null || !_mqttClient.IsConnected))
{
_ = TryReconnectAsync();
}
}
}
public void SetBrokerAddress(string brokerIp)
{
if (string.IsNullOrWhiteSpace(brokerIp))
return;
broker = brokerIp;
}
public void SetBrokerPort(string bport)
{
if (string.IsNullOrWhiteSpace(bport))
return;
int.TryParse(bport, out port);
}
private Task OnClientConnected(MqttClientConnectedEventArgs args)
{
OnMainThread(() =>
{
Log("✅ MQTT 已连接");
OnConnected?.Invoke();
if(OnConnected != null)
Log("OnConnected not null");
else
Log("OnConnected is null");
});
return Task.CompletedTask;
}
private async Task OnClientDisconnected(MqttClientDisconnectedEventArgs args)
{
OnMainThread(() =>
{
Log($"❌ 断开:{args.Reason}");
OnDisconnected?.Invoke(args.Reason.ToString());
});
if (_manualDisconnect || !PubMethod.ReconnectLanYiMgr)
return;
await TryReconnectAsync();
}
private Task OnApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs args)
{
var topic = args.ApplicationMessage.Topic;
var payload = Encoding.UTF8.GetString(args.ApplicationMessage.PayloadSegment);
OnMainThread(() => OnMessageReceived?.Invoke(topic, payload));
return Task.CompletedTask;
}
// 无限重连核心
private async Task TryReconnectAsync()
{
if (_isConnecting) return;
Log($"⏳ {reconnectInterval / 1000} 秒后自动重试...");
await Task.Delay(reconnectInterval);
if (!_manualDisconnect && PubMethod.ReconnectLanYiMgr)
{
await ConnectAsync();
}
}
public async Task DisconnectAsync()
{
_manualDisconnect = true;
try
{
if (_cts != null)
{
_cts.Cancel();
_cts.Dispose();
_cts = null;
}
if (_mqttClient != null)
await _mqttClient.DisconnectAsync();
}
catch { }
}
public async Task SubscribeAsync(string topic, MqttQualityOfServiceLevel qos = MqttQualityOfServiceLevel.AtMostOnce)
{
if (_mqttClient == null || !_mqttClient.IsConnected) { Log("未连接"); return; }
try { await _mqttClient.SubscribeAsync(topic, qos); Log($"已订阅:{topic}"); }
catch (Exception ex) { Log($"订阅失败:{ex.Message}"); }
}
public async Task PublishAsync(string topic, string payload, MqttQualityOfServiceLevel qos = MqttQualityOfServiceLevel.AtMostOnce, bool retain = false)
{
if (_mqttClient == null || !_mqttClient.IsConnected) { Log("未连接"); return; }
try
{
var msg = new MqttApplicationMessageBuilder()
.WithTopic(topic).WithPayload(payload)
.WithQualityOfServiceLevel(qos).WithRetainFlag(retain).Build();
await _mqttClient.PublishAsync(msg);
Log($"发布 [{topic}]:{payload}");
}
catch (Exception ex) { Log($"发布失败:{ex.Message}"); }
}
public async Task PublishAsync(string payload)
{
await MqttMgr.Instance.PublishAsync("lanyi/yiyue", payload);
}
private void Log(string msg) => OnMainThread(() => {
//Debug.Log($"[MQTT] {msg}"); OnLog?.Invoke(msg);
});
private void OnMainThread(Action act) => UnityMainThreadDispatcher.Instance.Enqueue(act);
private async void OnDestroy() => await DisconnectAsync();
}
UnityMainThreadDispatcher.cs
cs
using System;
using System.Collections.Generic;
using UnityEngine;
public class UnityMainThreadDispatcher : MonoBehaviour
{
public static UnityMainThreadDispatcher Instance { get; private set; }
private readonly Queue<Action> _queue = new Queue<Action>();
private void Awake()
{
if (Instance != null)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
public void Enqueue(Action action)
{
lock (_queue)
{
_queue.Enqueue(action);
}
}
private void Update()
{
lock (_queue)
{
while (_queue.Count > 0)
_queue.Dequeue()?.Invoke();
}
}
}
使用
cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
public class MQTTManager : MonoBehaviour
{
[Header("MQTT连接状态")]
public Image imgMqttStatus1;//首页显示
public InputField inputBrokerIp;
public InputField inputBrokerPort;
public Text textPrompt;
public Button btnConnect;
//记录之前是否连接
bool preConnected = false;
bool isMqttConnected
{
get
{
if (MqttMgr.Instance != null)
return MqttMgr.Instance.isMqttConnected;
return false;
}
}
async void Start()
{
btnConnect.onClick.AddListener(OnClickBtnConnect);
if (!MqttMgr.IsInitialized)
{
var mqtt = MqttMgr.Instance;
mqtt.OnConnected += OnConnectionSuccee;
mqtt.OnDisconnected += OnDisconnected;
}
inputBrokerIp.text = PlayerPrefs.GetString("brokerIp", "127.0.0.1");
inputBrokerPort.text = PlayerPrefs.GetString("brokerPort", "1883");
MqttMgr.Instance.SetBrokerAddress(inputBrokerIp.text.Trim());
MqttMgr.Instance.SetBrokerPort(inputBrokerPort.text.Trim());
// 连接
await MqttMgr.Instance.ConnectAsync();
}
float sumDeltaTime = 0.0f;
// Update is called once per frame
void Update()
{
if (Time.frameCount % 5 == 0)
{
if (preConnected != isMqttConnected)
{
if (isMqttConnected)
{
OnConnectionSuccee();
}
else
{
OnDisconnected("");
}
preConnected = isMqttConnected;
}
}
if(MqttMgr.Instance.isMqttConnected)
{
sumDeltaTime += Time.deltaTime;
if (sumDeltaTime > 5.0f)
{
sumDeltaTime = 0.0f;
//发送心跳消息
//CmdC0 cmdC0 = new CmdC0();
//cmdC0.ip = _localIP;
//cmdC0.sbh = _bindLanYiDeviceNo;
//MqttMgr.Instance.PublishAsync(JsonUtility.ToJson(cmdC0));
}
}
}
async void OnClickBtnConnect()
{
if (string.IsNullOrWhiteSpace(inputBrokerIp.text))
{
Message("请输入IP地址");
return;
}
if (string.IsNullOrWhiteSpace(inputBrokerPort.text))
{
Message("请输入端口号");
return;
}
PlayerPrefs.SetString("brokerIp", inputBrokerIp.text.Trim());
PlayerPrefs.SetString("brokerPort", inputBrokerPort.text.Trim());
if (MqttMgr.IsInitialized)
{
await MqttMgr.Instance.DisconnectAsync();
}
MqttMgr.Instance.SetBrokerAddress(inputBrokerIp.text.Trim());
MqttMgr.Instance.SetBrokerPort(inputBrokerPort.text.Trim());
//手动重连重置自动重连次数
await MqttMgr.Instance.ConnectAsync();
}
private void Message(string content)
{
textPrompt.text = content;
}
private async void OnConnectionSuccee()
{
await MqttMgr.Instance.SubscribeAsync("yiyue/lanyi");
MqttMgr.Instance.OnMessageReceived += OnProcessMessage;
if (PubMethod.UseShakeSignal == 1)
{
imgMqttStatus1.color = Color.green;
}
}
private void OnDisconnected(string reson)
{
if (PubMethod.UseShakeSignal == 1)
{
imgMqttStatus1.color = Color.gray;
}
}
private void OnProcessMessage(string topic, string msg)
{
if (topic == MqttMgr.Instance.MqttTopic)
{
//解析MQTT消息
}
}
private async Task OnDisable()
{
if(MqttMgr.Instance != null)
await MqttMgr.Instance.DisconnectAsync();
}
}