M2Mqtt断网重连

在使用M2Mqtt.dll这个控件时候,对于断网后,按照网上的说法,是处于broken状态,而且这个状态基本是不会主动改变的,在连接后,还是不能重新收发数据,而且这个控件当中,Ping检索是使用的1分钟检索一次,再次内部处理操作时,往往会超过5分钟左右,对 于现实开发的项目来说,非常不实用,方便。而且也查找了一些网上说的断网重连的方式,感觉要么是不用能,要么是缺少关键性的东西,所以,经过自己研究以后,修改了一下原代码并且加了外部处理,解决了断网重连的问题,下面分享一下,希望能够帮助到后续的使用人员。

首先,打开M2Mqtt这个项目,打开MqttClient这个类,修改KeepAliveThread()这个线程方法,将this.keepAliveEvent.WaitOne(wait);改为this.keepAliveEvent.WaitOne(1000);,这是要求等待时间从原来的60000改为1000,也就是1分钟改为1秒钟。修改注释掉if (delta >= this.keepAlivePeriod)这个语句,包括块else里的内容,一起注释掉,这个方法下面,加上this.Ping();这个是保证在不能保证时间是否超时之前,强行去执行Ping校验,通过校验结果判断是否关闭Mqtt。

第二,在外部调用时,在M2Mqtt连接成功时,开启一个线程,循环监控当前连接状态,如果连接断开,重新连接,这个时候,一定要记住当前连接的Clientid、user、password、订阅主题和发布主题等信息,以免不能够及时连接后,接收后续的消息。因为在mqtt判断ping连接断开后,mqtt内部会自动断开连接,所以这个时候,我们不用手动去断开连接,但重连时,mqtt会自动搜索当前的clientid,所以这个时间有些长,而且第一次时会抛出错误,第二次连接时,才会成功,这个具体机制没有研究。

下面分享一下代码,可以做一个参考:

MqttClient.cs内修改代码:

/// <summary>
        /// Thread for handling keep alive message
        /// </summary>
        private void KeepAliveThread()
        {
            int delta = 0;
            int wait = this.keepAlivePeriod;
            
            // create event to signal that current thread is end
            this.keepAliveEventEnd = new AutoResetEvent(false);

            while (this.isRunning)
            {
#if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3 || COMPACT_FRAMEWORK)
                // waiting...
                this.keepAliveEvent.WaitOne(wait, false);
#else
                // waiting...
                this.keepAliveEvent.WaitOne(1000);//wait);
#endif

                if (this.isRunning)
                {
                    delta = Environment.TickCount - this.lastCommTime;

                    // if timeout exceeded ...
//                    if (delta >= this.keepAlivePeriod)
//                    {
//#if BROKER
//                        // client must close connection
//                        this.OnConnectionClosing();
//#else
//                        // ... send keep alive
//                        this.Ping();
//                        wait = this.keepAlivePeriod;
//#endif
//                    }
//                    else
//                    {
//                        // update waiting time
//                        wait = this.keepAlivePeriod - delta;
//                    }
                    this.Ping();
                    wait = this.keepAlivePeriod;
                }
            }

            // signal thread end
            this.keepAliveEventEnd.Set();
        }

外部调用代码:

mqttClient = new MqttClient(Address);

mqttClient.MqttMsgPublishReceived += mqttClient_MqttMsgPublishReceived;//发布主题后接收消息事件

string userName = UserName;
string passWord = PassWord;

try
                    {
                        string clientid = Guid.NewGuid().ToString();
                        byte res = mqttClient.Connect(clientid, userName, passWord);
                        MqttClientCheckedStatusEventArgs e = new MqttClientCheckedStatusEventArgs();
                        e.ClientId = clientid;
                        e.PassWord = passWord;
                        e.UserName = userName;
                        e.IsConnected = mqttClient.IsConnected;
                        e.Client = mqttClient;
                        if (res == 1)
                            throw new Exception("MQTT, 服务端不支持客户端请求的MQTT协议级别");
                        else if (res == 2)
                            throw new Exception("MQTT, 客户端标识符是正确的UTF-8编码,但服务端不允许使用");
                        else if (res == 3)
                            throw new Exception("MQTT, 网络连接已建立,但MQTT服务不可用");
                        else if (res == 4)
                            throw new Exception("MQTT, 无效的用户名或密码");
                        else if (res == 5)
                            throw new Exception("MQTT, 客户端未被授权连接到此服务器");
                        else if (res != 0)
                            throw new Exception("MQTT, 未知错误");
                        else
                        {
                            //"MQTT, 连接已被服务端接受"
                            string[] topics = ((List<string>)ma.SubscribeList).ToArray();
                            byte[] qoslevel = new byte[topics.Length];// { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE };
                            e.Topics = topics;
                            e.Qoslevels = qoslevel;
                            for (int j = 0; j < qoslevel.Length; j++)
                            {
                                qoslevel[j] = MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE;
                            }
                            if (mqttClient.IsConnected)
                            {
                                mqttClient.Subscribe(topics, qoslevel);
                                //FileLibrary.LogInfo.WriteLog("订阅主题成功");
                            }
                            else
                            {
                                throw new Exception("与服务器未建立连接");
                            }
                        }
                        Tx.StartThread(new ParameterizedThreadStart(CheckedStatus), e);
                        break;
                    }
                    catch (Exception ex)
                    {
                        try
                        {
                            mqttClient.Disconnect();
                        }
                        catch { }
                        throw new Exception(ex.Message);
                    }

 

/// <summary>
        /// 检查状态改变事件
        /// </summary>
        /// <param name="sender"></param>
        private void CheckedStatus(object sender)
        {
            MqttClientCheckedStatusEventArgs e = sender as MqttClientCheckedStatusEventArgs;
            while (SourceLibrary.CommonParame.IsStart)
            {
                if (!e.Client.IsConnected)
                {
                    try
                    {
                        byte res = e.Client.Connect(e.ClientId, e.UserName, e.PassWord);
                        if (res == 0)
                        {
                            e.Client.Subscribe(e.Topics, e.Qoslevels);
                        }
                    }
                    catch(Exception ex) { }
                }
                if (MqttChangedStatusEvent != null)
                    MqttChangedStatusEvent.Invoke(this, e);
                Thread.Sleep(500);
            }
        }

 

需要的事件:

public class MqttReceivedMessageEventArgs : EventArgs
    {
        /// <summary>
        /// 收到的消息
        /// </summary>
        public string Message
        { get; set; }
        /// <summary>
        /// 返回的主题
        /// </summary>
        public string Topic
        { get; set; }
    }

    public class MqttClientCheckedStatusEventArgs : EventArgs
    {
        /// <summary>
        /// 连接状态
        /// </summary>
        public bool IsConnected
        { get; set; }
        /// <summary>
        /// 连接的用户名
        /// </summary>
        public string UserName
        { get; set; }
        /// <summary>
        /// 连接的密码
        /// </summary>
        public string PassWord
        { get; set; }
        /// <summary>
        /// 连接的客户端ID
        /// </summary>
        public string ClientId
        { get; set; }
        /// <summary>
        /// 连接的客户端
        /// </summary>
        public MqttClient Client
        { get; set; }
        /// <summary>
        /// 订阅主题
        /// </summary>
        public string[] Topics
        { get; set; }
        /// <summary>
        /// QOS_LEVEL_AT_MOST_ONCE
        /// </summary>
        public byte[] Qoslevels
        { get; set; }
    }

需要的委托:

/// <summary>
    /// 收到MQTT主题返回消息事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void MqttReveivedMessageEvent(object sender, MqttReceivedMessageEventArgs e);
    /// <summary>
    /// 检测MQTT状态
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    delegate void MqttCheckedClientStatusEvent(object sender, MqttClientCheckedStatusEventArgs e);

需要的事件:

/// <summary>
        /// 收到订阅主题返回消息事件
        /// </summary>
        public event MqttReveivedMessageEvent MqttReveivedMessageComTemplate;
        /// <summary>
        /// Mqtt连接状态改变事件
        /// </summary>
        public event MqttCheckedClientStatusEvent MqttChangedStatusEvent;

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值