WCF服务器向客户端播送消息和心跳检测

来源:互联网 发布:手机游戏下载java 编辑:程序博客网 时间:2024/05/01 07:57

        在利用WCF服务的时候,通常只是在服务器监听客户端调用服务。但是WCF服务本就是对TCP, HTTP等各种通信方式的封装了所有SOCKET能够实现的东西,WCF服务应该也能实现。

        前面写过一次博客,利用WCF服务的会话模式实时检测客户端异常掉线。但是对于拔出网线的异常并没有反应。在这里我们利用WCF服务的双工通信来在服务器进行心跳检测,以识别客户端的掉线.。同时利用双工通信向多个已经连接客户端播送消息。

       所有的操作正如前面一篇博客一样都是建立在WCF服务会话模式的基础上。

1。心跳

        前篇已经解释过为何要用会话模式了,不再多说。直接看步骤

1>. 先在WCF服务 IService 里面定义回调接口。回调函数在客户端实现 这里不再列出 如下

[ServiceContract(CallbackContract =(typeof(IDataServiceCallback)))] public interface IDataServiceCallback    {        [OperationContract(IsOneWay =true)]        void SendBeat();    }


2>.  在Service.svc 中开启会话模式,并在构造函数中开启心跳线程

 [ServiceBehavior(IncludeExceptionDetailInFaults =true,InstanceContextMode =InstanceContextMode.PerSession,ConcurrencyMode =ConcurrencyMode.Multiple)]
  OperationContext context;        MessageProperties properties;        RemoteEndpointMessageProperty endpoint;        string loginID = null;        IDataServiceCallback callback;        private string loginState;        Thread th;        public DataService()        {            context = OperationContext.Current;    //获取登录的时间和IP            properties = context.IncomingMessageProperties;            //获取消息发送的远程终结点IP和端口            endpoint = properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;            loginState = "登录成功";            callback = context.GetCallbackChannel<IDataServiceCallback>();            th = new Thread(TestBeat);            th.IsBackground = true;            th.Start();        }
在线程中每隔5秒钟调用一次回调函数,并用try{}catch{}块包围

  public void TestBeat()        {            try            {                while (true)                {                    Thread.Sleep(5000);                    try                    {                        callback.SendBeat();                    }                    catch(CommunicationException)                    {                        userInfoDAL.UpdateState(endpoint.Address, false, loginState);                        UserInfoDataSource.UpdateRowOut(endpoint.Address, loginState);                    }                }            }            catch (ThreadAbortException) { }        }
如上代码所示,如果C-S之间的网线被拔出 就能catch到错误此时会话就会终止,你便可以在catch中将你保存的连接用户剔除,或者如上篇所属在Dispose()中剔除, 因为如果信道出错会话终止,此实例就会调用Dispose()函数注销此类. 服务器心跳先到这儿


2。服务器向客户端单播或多播消息。

         同样是利用双工通信。正如Socket一样 服务器保存所有的连接的客户端Socket WCF服务同样也需要保存这样类似的东西。但是什么,经过一番研究和推导,它就是服务实例Service 即Service.svc的实例化对象。下面看步骤

1>. 先在WCFService项目中添加一个类,用于存储连接的服务实例

 public class Users    {        public static List<Service1> listChannel = new List<Service1>();        public static void Add(Service1 service1)        {            listChannel.Add(service1);        }    }

2>. 然后再Service.svc的构造函数中保存所有连接的服务实例

  public Service1()        {            callback = OperationContext.Current.GetCallbackChannel<ICalculatorCallback>();                 Users.Add(this);        }

3>. 多播数据 这里我只展示多播函数,单播只要找对应客户端IP就好。

先定义多播契约函数

   [OperationContract]        void BroadCast(string str);
实现多播函数

  public void BroadCast(string str)        {            Console.WriteLine("获得[" + remp.Address + ":" + remp.Port + "]发送过来的消息:" + str);            foreach (Service1 context in Users.listChannel)            {                context.callback.SendString(remp.Address, remp.Port, str);            }        }
然后我们就可以在客户端利用多播函数向其他客户端发送消息了。 下面是我试验截图



从左到右依次是三个客户端,每个客户端都调用一次多播向其他客户端发送消息. 如第一个 先向服务发送消息,然后自己接到服务发的消息,然后是我的一些测试。 在最后收到第二和第三个客户端发来的消息。第二个客户端最后只接受到第三个客户端发来的消息。与Socket 编程效果完全一样甚至更方便。

 


0 0
原创粉丝点击