MQTT:C#实现断线重连
工作中遇到的问题,记录在这里。
网络异常等原因被动断开连接
错误写法
以订阅端为例,下面的方法,主要写核心代码,一些判断省略...
private MqttClient client;
//创建客户端并连接
private void CreateClient(Action<object, MqttMsgPublishEventArgs> callBack)
{
//1.创建客户端
client = new MqttClient("xx.xx.xx.xx");
//2.为MqttMsgPublishReceived 事件绑定方法,当订阅到消息时执行callBack委托方法
client.MqttMsgPublishReceived += (sender, e) =>
{
callBack.Invoke(sender, e);
};
//3.建立连接
string clientid = Guid.NewGuid().ToString();
byte result = client.Connect(clientid, "username", "password");
//4.为ConnectionClosed连接断开事件绑定一个回调方法
client.ConnectionClosed += delegate
{
Task.Factory.StartNew(() =>
{
while (client== null || client.IsConnected == false)
{
Thread.Sleep(5 * 1000);
CreateClient(callBack);
}
}).ConfigureAwait(false);
};
}
//订阅,省略了判断步骤,保留核心代码
public void SubTopic(string topic, Action<object, MqttMsgPublishEventArgs> callBack)
{
//创建客户端并连接代理
var result = CreateClient(callBack);
//订阅主题
client.Subscribe(new string[] { topic }, new byte[] { 1 });
}
//模拟main方法调用SubTopic,进行订阅操作
SubTopic("topic", ReceiveProcessDataMqtt);
对于以上代码,关键是在CreateClient方法的步骤4,当网络异常断开后,会进入里面的while循环每隔5秒进行重新连接,实际上这里是可以连接成功的,但是在真实场景中会发现并不会出现重连后订阅消息的效果,正确的写法如下:
ClientDebug.ConnectionClosed += delegate
{
Task.Factory.StartNew(() =>
{
while (client== null || client.IsConnected == false)
{
Thread.Sleep(5 * 1000);
CreateClient(topic, callBack);
SubTopic(topic, callBack);
}
}).ConfigureAwait(false);
};
对比前后两段ConnectionClosed事件绑定的代码,发现区别在加了一句SubTopic(topic, callBack);为什么会这样呢?原理其实很简单,在上面的CreateClient方法里的步骤3.建立连接,我们并没有指定cleansession 清除会话的字段,意味着因为连接broker的时候cleansession没设置,默认是true,只要断线就会把和代理建立的连接信息(包括订阅信息)删除,当再次重连了之后就必须重新订阅才能真正实现断线重连的效果;也可以在connect的时候将cleansession字段设置为false,这样断线重连后客户端和broker之间仍然保持之前订阅的状态,就可以直接订阅。注意:这里为CreateClient()方法增加了一个入参,传入要订阅的主题。
遗留问题:本文的情况是针对断开连接后自动重新连接;那如果同样是调用了上面的方法后,这时候我想主动去断开连接后不再让程序自动建立连接,该怎么办?我将在这篇进行解答MQTT:主动断开连接,并清除客户端事件绑定的所有委托