基于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();
        }

       
    }
}

服务器端无需额外的设置。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏葡萄城控件技术团队

ASP.NET 5系列教程(七)完结篇-解读代码

在本文中,我们将一起查看TodoController 类代码。 [Route] 属性定义了Controller的URL 模板: [Route("api/[con...

22250
来自专栏跟着阿笨一起玩NET

winform 窗体实现增删改查(CRUD)窗体基类模式

参考博客下方:http://www.cnblogs.com/wuhuacong/archive/2010/05/31/1748579.html

37920
来自专栏用户2442861的专栏

Java:HttpClient篇,HttpClient4.2在Java中的几则应用:Get、Post参数、Session(会话)保持、Proxy(代理服务器)设置,多线程设置...

新版HttpClient4.2与之前的3.x版本有了很大变化,建议从http://hc.apache.org/处以得到最新的信息。

27010
来自专栏木宛城主

ASP.NET那点不为人知的事(二)

上一篇博文《ASP.NET那点不为人知的事(一)》中我们提到HttpApplication有19个标准事件,在HttpApplication的第8个事件P...

23150
来自专栏跟着阿笨一起玩NET

WinForm程序启动控制台窗口Console

本文转载:http://blog.csdn.net/oyi319/article/details/5753311

30910
来自专栏智能大石头

【SmartOS】轻量级多任务调度系统

SmartOS是一个完全由新生命团队设计的嵌入式操作系统,主要应用于智能家居、物联网、工业自动化控制等领域。 ARM Cortex-M系列微处理器几乎全都做成...

432110
来自专栏技术博客

菜菜从零学习WCF九(会话、实例化和并发)

在服务协定上设置System.ServiceModel.ServiceContractAttribute.SessionMode值

10830
来自专栏Ken的杂谈

C# MD5加密-MD5Helper

3.5K30
来自专栏AhDung

C#程序防多开又一法

在Main()方法开始时遍历所有进程,获取每个进程的程序集GUID和PID,若发现有跟自己GUID相同且PID不同的进程,就勒令自身退出。

26830
来自专栏施炯的IoT开发专栏

windows mobile窗口之间传递数据的方法

    在windows mobile上设计UI的时候,经常会碰到多个窗口的情况。有时候,我们需要将一个窗口中的用户输入信息反应到另一个窗口中去,这就涉及到窗口...

20690

扫码关注云+社区

领取腾讯云代金券