基於TCP通信的客戶端斷線重連


基於TCP通信的客戶端斷線重連

 

轉載:http://www.cnblogs.com/networkcomms/p/4304362.html

源碼下載

在CS程序中,斷線重連應該是一個常見的功能。

此處的斷線重連主要指的是服務器端因為某種故障,服務器端程序或者系統進行了重新啟動,客戶端能夠自動探測到服務器端掉線,並嘗試重新進行連接

本程序基於來自英國的開源c#通信框架的networkcomms(2.3.1版本)

先看一下效果

初始狀態:

當服務器端程序關閉后,客戶端會自動探測到,並在客戶端顯示相關信息

然后,我們設定為每隔5秒重連一次,可以自定義設置重連的次數,比如說重連50次,如果還沒有重連成功,則放棄重連

然后我們重新啟動服務器端,客戶端會顯示重連成功.

具體步驟如下:

需要修改幾處NetworkComms2.3.1通信框架中的代碼

第一步:修改ConnectionInfo類的NoteConnectionShutdown方法

該方法原來是:

   internal void NoteConnectionShutdown()
        {
            lock (internalLocker)
                ConnectionState = ConnectionState.Shutdown;
        }

修改后為: 

復制代碼
復制代碼
   private bool reconnectFlag = false;
        /// <summary>
        /// 是否為重連接模式
        /// </summary>
        public bool ReconnectFlag
        {
            get { return reconnectFlag; }
            set { reconnectFlag = value; }
        }

        /// <summary>
        /// Note this connection as shutdown
        /// </summary>
        internal void NoteConnectionShutdown()
        {
            lock (internalLocker)
                ConnectionState = ConnectionState.Shutdown;
            //添加以下代碼  初始狀態為False  觸發連接狀態改變事件
            if (reconnectFlag == false)
            {
                StateChanged.Raise(this, new StringEventArgs("連接出現異常"));
            }

        }

        //添加狀態改變事件 

        public event EventHandler<StringEventArgs> StateChanged;
復制代碼
復制代碼

 

第二步:在NetworkComms庫類中添加相關的代碼如下:

復制代碼
using System;
using System.Collections.Generic;
using System.Text;
using NetworkCommsDotNet.Tools;

namespace NetworkCommsDotNet
{
    public static class Extensions
    {
        public static void Raise<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs
        {
            if (handler != null)
                handler(sender, args);
        }

    }

    public class StringEventArgs : EventArgs
    {
        public StringEventArgs(string text)
        {
            Text = text;
        }
        public string Text { get; set; }

    }
  
}

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)]
    public sealed class ExtensionAttribute : Attribute { }
}
復制代碼

第三步:在NetworkComms靜態類中添加如下方法:

復制代碼
復制代碼
 public static void ClearDic()
        {
            lock (globalDictAndDelegateLocker)
            {
                allConnectionsById.Clear();

                allConnectionsByEndPoint.Clear();

                oldNetworkIdentifierToConnectionInfo.Clear();
            }
        }
復制代碼
復制代碼

如果您使用的是V3版本,代碼稍微變化:

復制代碼
復制代碼
 public static void ClearDic()
        {
            lock (globalDictAndDelegateLocker)
            {
                allConnectionsByIdentifier.Clear();

                allConnectionsByEndPoint.Clear();

                oldNetworkIdentifierToConnectionInfo.Clear();
            }
        }
復制代碼
復制代碼

客戶端代碼:

復制代碼
復制代碼
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using NetworkCommsDotNet;
using DPSBase;
using System.Net;
using System.Threading;

namespace AppClient
{
    public partial class Form1 : Form
    {
        //連接信息類
        public ConnectionInfo connnectionInfo = null;

        //連接類
        Connection connection;


        public Form1()
        {
            InitializeComponent();
          
        }

        //在窗體上顯示新信息
        void Form_ConnectionStatusNotify(object sender, StringEventArgs e)
        {
            if (this.InvokeRequired)
            {

                this.Invoke(new EventHandler<StringEventArgs>(this.Form_ConnectionStatusNotify), sender, e);
            }
            else
            {

                lblLink.Text = e.Text;
                lblLink.ForeColor = Color.Blue;
            }
        }

        private bool ServerNotifyClose = false;

        public event EventHandler<StringEventArgs> ConnectionStatusNotify;

        void connnectionInfo_StateChanged(object sender, StringEventArgs e)
        {
            //如果不是服務器通知關閉,則自動重連,如果是服務器通知關閉,則不作處理
            //本Demo中沒有使用ServerNotifyClose
            if (ServerNotifyClose == false)
            {
                //更新連接信息類  設置為重連模式
                connnectionInfo.ReconnectFlag = true;
                 
                ConnectionStatusNotify.Raise(this, new StringEventArgs("可能由於服務器的故障,與服務器端的連接已斷開"));

                int num = 0;
                int retryCount = 30;
                int retrySpanInMSecs = 5000;


                do
                {
                    try
                    {
                        NetworkComms.ClearDic();

                        connection = TCPConnection.GetConnection(connnectionInfo);
                         
                          
                        ConnectionStatusNotify.Raise(this, new StringEventArgs("重連成功"));

                        connnectionInfo.ReconnectFlag = false;

                        break;
                    }
                    catch (Exception ex)
                    {
                        num++;
                        if (num < retryCount)
                        {
                            
                            ConnectionStatusNotify.Raise(this, new StringEventArgs("正在進行第" + num + "次重連"));
                            Thread.Sleep(retrySpanInMSecs);
                        }
                    }
                }
                while (num < retryCount);

            }
        }
         

        private void button1_Click(object sender, EventArgs e)
        { 

            connnectionInfo = new ConnectionInfo(txtIP.Text, int.Parse(txtPort.Text));

            //如果不成功,會彈出異常信息
            connection = TCPConnection.GetConnection(connnectionInfo);

            button1.Enabled = false;
            button1.Text = "連接成功";

            //訂閱連接信息類中的連接狀態改變事件
            connnectionInfo.StateChanged += new EventHandler<StringEventArgs>(connnectionInfo_StateChanged);
            this.ConnectionStatusNotify += new EventHandler<StringEventArgs>(Form_ConnectionStatusNotify);
        }

        //獲取水果相關信息
        private void button2_Click(object sender, EventArgs e)
        {
            if (listBox1.SelectedIndex > -1)
            { 
                string resMsg = connection.SendReceiveObject<string>("ReqFruitEngName", "ResFruitEngName", 5000, listBox1.Text);
                 
                MessageBox.Show("您選擇的水果的英文名稱是:" + resMsg);

            }
            else
            {
                MessageBox.Show("請選擇一項");
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {

            this.Dispose();
        }

       
    }
}
復制代碼
復制代碼

服務器端無需額外的設置。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM