zoukankan      html  css  js  c++  java
  • WCF心跳判断服务端及客户端是否掉线并实现重连接

    本篇文章将通过一个实例实现对WCF中针对服务端以及客户端是否掉线进行判断;若掉线时服务器或客户端又在线时将实现自动重连;将通过WCF的双工知识以及相应的心跳包来实现此功能;

    首先了解一下本实例的一个分层架构图;相信了解WCF对这个分层法肯定都很了解;其中Client为客户端,Interface为契约层,Service则是实现契约的服务层;

    接下来我们将对各层进行一个简单的讲解;方便大家理解实例的实现方式;

    首先我们了解契约层Interface;因为我们利用WCF中的双工知识,所以此处我们定义的两个接口,其中ICallback为回调接口;IPushMessage上面定义的回调;我们发现回调接口上并没有定义ServiceContract; 其实是WCF当一个接口被定义成回调接口时已经默认了;

    复制代码
    using System.ServiceModel;
    namespace Interface
    {
        [ServiceContract(SessionMode=SessionMode.Required,CallbackContract=typeof(ICallback))]
        public interface IPushMessage
        {
            [OperationContract(IsOneWay = true)]
            void Login(string UID);
    
            [OperationContract(IsOneWay = true)]
            void Update(string UID);
    
            [OperationContract(IsOneWay = true)]
            void Leave(string UID);
        }
    }
    复制代码
    复制代码
    using System.ServiceModel;
    namespace Interface
    {
        public interface ICallback
        {
            [OperationContract(IsOneWay = true)]
            void ShowMessage(string msg);
        }
    }
    复制代码


    接着我们了解一下实现契约的服务层Service;此处包括实现接口IPushMessage的服务内容,还定义一个类WcfCleint;在PushMessageServer服务内里我们定义的一个静态成员Dictionary<string,WcfCleint>用于记录我们客户端上下线的操作;定义的一个lockObje用来锁定每个操作,在最后我们还定义的一个定时器用来判断客户端用户是否脱机了;其中方法Update()我们就实现的双工中的回调;

    复制代码
    using System.ServiceModel;
    using Interface;
    namespace Service
    {
        public class PushMessageServer:IPushMessage
        {
            static Dictionary<string, WcfCleint> dit_callback = new Dictionary<string, WcfCleint>();
    
            private static Object lockObje = new Object();
    
            public void Login(string UID)
            {
                Console.WriteLine("用户:" + UID + "上线");
                lock (lockObje)
                {
                    dit_callback.Add(UID, new WcfCleint(OperationContext.Current.GetCallbackChannel<ICallback>(), DateTime.Now));
                }
            }
    
            public void Update(string UID)
            {
                ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
                Console.WriteLine("用户:" + UID + "心跳更新!");
                lock (lockObje)
                {
                    if (dit_callback.ContainsKey(UID))
                    {
                        dit_callback.Remove(UID);
                    }
                    dit_callback.Add(UID, new WcfCleint(OperationContext.Current.GetCallbackChannel<ICallback>(), DateTime.Now));
                    callback.ShowMessage(UID);
                }
            }
    
            public void Leave(string UID)
            {
                Console.WriteLine("用户:" + UID + "退出!");
                lock (lockObje)
                {
                    dit_callback.Remove(UID);
                }
            }
    
            static System.Timers.Timer timer1;
            public static void StartListenClients()
            {
                timer1 = new System.Timers.Timer();
                timer1.Interval = 500;
                timer1.Elapsed += new System.Timers.ElapsedEventHandler(time_EventArgs);
                timer1.Start();
            }
    
            static void time_EventArgs(object sender, System.Timers.ElapsedEventArgs e)
            {
                lock (lockObje)
                {
                    foreach (string key in new List<string>(dit_callback.Keys))
                    {
                        if (dit_callback[key].NowdateTime.AddSeconds(5) < DateTime.Now)
                        {
                            dit_callback.Remove(key);
                            Console.WriteLine("脱机用户" + key);
                        }
                    }
                }
            }
        }
    }
    复制代码


    接着我们简单看一下WcfCleint的代码:

    复制代码
    using Interface;
    using System.ServiceModel;
    namespace Service
    {
        public class WcfCleint
        {
            public DateTime NowdateTime { get; set; }
            public ICallback callbackHandler { get; set; }
    
            public WcfCleint(ICallback callback, DateTime nowTime)
            {
                this.callbackHandler = callback;
                this.NowdateTime = nowTime;
            }
        }
    }
    复制代码


    服务端的配置文件信息,此处我们采用net.tcp方式:

    复制代码
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <behaviors>
          <serviceBehaviors>
            <behavior name="exposeExceptionDetail">
              <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <services>
          <service name="Service.PushMessageServer"
                   behaviorConfiguration="exposeExceptionDetail">
            <endpoint address="net.tcp://127.0.0.1:3721/PushMessageServer"
                      binding="netTcpBinding"
                      contract="Interface.IPushMessage"/>
          </service>
        </services>
      </system.serviceModel>
    </configuration>
    复制代码


    服务端的运行入口代码,通过一个线程不断的运行:

    复制代码
    using System.Threading;
    using System.ServiceModel.Description;
    namespace Service
    {
        class Program
        {
            static void Main(string[] args)
            {
                using (ServiceHost host = new ServiceHost(typeof(PushMessageServer)))
                {
                    host.Open();
                    Console.WriteLine("WCF心跳包实现开始监听");
                    PushMessageServer.StartListenClients();
                    int i = 0;
                    while (true)
                    {
                        System.Threading.Thread.Sleep(2000);
                        i++;
                    }
                    Console.Read();
                    host.Abort();
                    host.Close();
                }
            }
        }
    }
    复制代码


    接着了解客户端层的情况;首先是一个实现的回调接口的内容类;

    复制代码
    using Interface;
    namespace Client
    {
        public class CallServer:ICallback
        {
            public void ShowMessage(string msg)
            {
                Console.WriteLine("服务器正在工作中;" + msg);
            }
        }
    }
    复制代码

    客户端的配置信息如下:

    复制代码
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <client>
          <endpoint name="pushmessageserver"
                    address="net.tcp://127.0.0.1:3721/PushMessageServer"
                    binding="netTcpBinding"
                    contract="Interface.IPushMessage"/>
        </client>
      </system.serviceModel>
    </configuration>
    复制代码

    客户端的运行入口代码如下,它会判断服务器是否掉线,若掉线会试着重连:

    复制代码
    using System.ServiceModel;
    using Interface;
    using System.ServiceModel.Channels;
    using System.Threading;
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                InstanceContext callback = new InstanceContext(new CallServer());
                using (DuplexChannelFactory<IPushMessage> channelFactory = new DuplexChannelFactory<IPushMessage>(callback, "pushmessageserver"))
                {
                    IPushMessage proxy = channelFactory.CreateChannel();
                    using (proxy as IDisposable)
                    {
                        string UID = "踏浪帅";
                        proxy.Login(UID);
    
                        while (true)
                        {
                            Thread.Sleep(3000);
                            try
                            {
                                proxy.Update(UID);
                            }
                            catch
                            {
                                try
                                {
                                    Console.WriteLine("正在重连");
                                    proxy = channelFactory.CreateChannel();
                                    proxy.Login(UID);
                                }
                                catch
                                {
                                    Console.WriteLine("重连异常");
                                }
                            }
                        }
                    }
                }
                Console.Read();
            }
        }
    }
    复制代码


     

    代码的内容就如上,接着我们简单看一下运行的效果:

    1:首先运行服务端,让其处于监听

    2:接着运行客户端,客户端会显示服务器正在工作中以及当前的账号

    3:当客户端上线后,服务端就发现客户端用户,并显示出来,不停的进行判断

    4:当我们把服务端停掉以后,此时服务是不工作的,我们可以看到客户端就会不停的尝试着重连服务端;

    5:当我们重新把服务端打开以后,服务端会自运发现正在运行的客户端信息;

    6:上面我们重新打开服务端,我们可以在客户端发现它重连接服务端成功并显示如下:

    7:接着我们将把客户端关闭;我们会在服务端发现它提示客户端的用户脱机了;

    8:此时服务端还是不停的监听中,我们再把客户端打开,服务端将会接着显示用户;

    实例为本人学习WCF知识所写,其中可能存在不足或错误,欢迎大家指正;若是本文对你有帮助别忘记点右下角帮忙推荐,毕竟有大家的支持才是我们写作的动力;

  • 相关阅读:
    209. Minimum Size Subarray Sum
    208. Implement Trie (Prefix Tree)
    207. Course Schedule
    206. Reverse Linked List
    205. Isomorphic Strings
    204. Count Primes
    203. Remove Linked List Elements
    201. Bitwise AND of Numbers Range
    199. Binary Tree Right Side View
    ArcGIS API for JavaScript 4.2学习笔记[8] 2D与3D视图同步
  • 原文地址:https://www.cnblogs.com/wei2yi/p/3248333.html
Copyright © 2011-2022 走看看