• 基于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();
            }
    
           
        }
    }
    复制代码
    复制代码

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

  • 相关阅读:
    前端知识体系(一)浏览器机制以及进程线程的关系
    页面之间的通信
    DOM
    浏览器内核及浏览器对象
    js正则表达式
    setTimeout和setInterval
    原生js操作cookie
    apply、call、bind方法调用
    一个简单的hexo搭建博客网站的故事
    debug for bin runtime error
  • 原文地址:https://www.cnblogs.com/Jeely/p/10972091.html
Copyright © 2020-2023  润新知