MQTT:C#实现断线重连

发布时间 2023-03-22 21:11:41作者: dreamw

工作中遇到的问题,记录在这里。

网络异常等原因被动断开连接

错误写法

以订阅端为例,下面的方法,主要写核心代码,一些判断省略...

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:主动断开连接,并清除客户端事件绑定的所有委托

 

转 https://www.jianshu.com/p/5ab6630a31ca