WCF 项目应用连载[1] - 索引 - 轻量级的Log系统 - Lig Sample -序

第二节我们已经创建了Lig项目,并且能稳定工作了。现在我们来改进ILigAgent接口,实现WCF的双向通信。

3.1 双向通信

_________________________________________________________________________________

ILigAgent 增加订阅-发布 接口

3.1.1 关于订阅 – 发布


1) 发布-订阅设计模式又称观察者模式,它是软件设计模式中的一种,有一点要明白,它并不是WCF中所特有,正好相反,WCF中的双向通信只是这种模式中的一种应用。

2) WCF采用回调接口来进行双向通信,每一个服务接口允许存在有且只能存在一个回调接口。可以用ServiceContract中的CallbackContract属性进行显式声明指定定该服务接口的回调接口。

3) 回调接口由客户端实现。Server端通过一个静态的OperationContext对象获取客户端回调实例,我们用该实例在Server端调用回调接口,即可将消息发送给Client端。

OperationContext.Current.GetCallbackChannel<T>

如你所愿

1) 我们为ILigAgent增加了RegisterClient操作接口与Subcribe接口,Subcribe用于订阅服务端的消息。

2) 同时增加了ILigAgentCallback回调接口,用来在Server端实现消息推送。回调接口我们增加OnNotifyOnline,用来客户端注册成功后,Server将生成的带ClientID信息的消息发送给注册的客户端。

注意:服务端不同的服务实例用不同的HashCode加以区分,这样允许同名客户端的存在。

    [ServiceContract(CallbackContract = typeof(ILigAgentCallback))]
public interface ILigAgent
{
[OperationContract]
LigStatus RegisterClient(string name);
[OperationContract]
LigStatus UnregisterClient(int clientID);
[OperationContract]
LigStatus Subscribe(int clientID);
[OperationContract]
LigStatus Unsubscribe(int clientID); }
public interface ILigAgentCallback
{
[OperationContract(IsOneWay = true)]
void OnNotifyMessage(string message);
[OperationContract(IsOneWay = true)]
void OnNotifyOnline(LigArgs args);
}

3.1.2 增加 数据契约类 LigArgs

说了半天。我们还没有正式应用数据契约。现在我们增加数据契约类用来在客户端与服务端进行通信时的数据传输。
此处LigArgs可以写成LigArgs : EventArgs,这样LigArgs可以变成EventHandler的事件参数岂不更好吗?

致于为什么不这样写,我们后面写ILigger时会回答这个问题。因为那时Lig已经完善。

    [DataContract]
public class LigArgs
{
public LigArgs() { }
[DataMember]
public int ClientID { get; set; }
[DataMember]
public int HashID { get; set; }
[DataMember]
public bool ConnectStatus { get; set; }
[DataMember]
public string ClientName { get; set; }
[DataMember]
public string Message { get; set; }
}

3.2 服务实例管理 – 增加客户端实例上下文类

_________________________________________________________________________________


1) 我们在LigAgent类的内部增加一个内部类ClientContext,即客户端实例上下文类,这儿用来描述所注册客户端的信息。

2) 同时增加一个静态表dicClientsContext,用来保存注册客户端信息,其键名采用独立的HashCode。

Client信息就可以保存在Server端,Server端通过CallbackInstance给订阅客户端发送订阅消息。当客户端异常离线,Server将离线客户端信息从dicClientsContext中移除,移除的Client信息会由GC自动实现垃圾回收(当然此处最佳方案是采用弱引用(WeakReference)对ClientContext进行管理在性能上会更高效)。这样实现了Server对客户端资源的有效管理。

private static Dictionary<int, ClientContext> dicClientsContext = new Dictionary<int, ClientContext>();
#region InnerClasses
class ClientContext
{
internal ClientContext() { }
internal bool IsRegistered { get; set; }
internal bool IsSubscribed { get; set; }
internal int ClientID { get; set; }
internal int HashID { get; set; }
internal string ClientName { get; set; }
internal ILigAgentCallback CallbackInstance { get; set; }
internal OperationContext Context { get; set; }
}
#endregion

3.3 客户端 – 增加LigAgentCallback类

_________________________________________________________________________________

1) 在ConnectServer中将ChannelFactory换成DuplexChannelFactory。

2) 并注册LigAgentCallback内部的事件。我们通过LigAgentCallback内部的事件将回调消息发送给客户端。

this.callbackInstance = new LigAgentCallback();
this.SubscribedEvents();
//this.chnl = new ChannelFactory<ILigAgent>(SERVICENAME);
this.chnl = new DuplexChannelFactory<ILigAgent>(callbackInstance,SERVICENAME); private delegate void MessageHandler(string message);
private delegate void OnlineHandler(LigArgs args); #region InnerClasses
class LigAgentCallback : ILigAgentCallback
{
internal LigAgentCallback() { }
internal event MessageHandler msgReceived;
internal event OnlineHandler onlined;
public void OnNotifyMessage(string message)
{
if (this.msgReceived != null)
{
this.msgReceived(message);
}
}
public void OnNotifyOnline(LigArgs args)
{
if (this.onlined != null)
{
this.onlined(args);
}
}
internal void Release()
{ }
}
#endregion

图 3.3.1 在 LigManager内部订阅 LigAgentCallback内部事件

3.4 关于服务端监控 - LigAgent

_________________________________________________________________________________

原理:LigManager封装了ILigAgent接口资源。在LigAgent内部通过注册OperationContext.Channel属性的Closed事件实现对客户端的异常与正常离线监控。

context.Context.Channel.Closed += new EventHandler(OnShowOffline)

LigAgent内部用于注册LigClient客户端的内部函数AddClient

        private LigStatus AddClient(string name,out int clientID)
{
clientID = -1;
int hash = this.GetHashCode();
if (string.IsNullOrEmpty(name)) return LigStatus.InvalidClient; if (dicClientsContext.ContainsKey(hash)) return LigStatus.ClientExisted; clientID = LigCore.ActiveID; ClientContext context = new ClientContext();
context.ClientID = clientID;
context.ClientName = name;
context.HashID = hash;
context.IsRegistered = true;
context.Context = OperationContext.Current;
context.CallbackInstance = OperationContext.Current.GetCallbackChannel<ILigAgentCallback>(); context.Context.Channel.Closed += new EventHandler(OnShowOffline); dicClientsContext.Add(hash, context);
Console.WriteLine(LigCore.LiggedTime + "Client with hashCode [" + hash.ToString() + "] is online!");
return LigStatus.Success;
}

3.5 双向通信 服务端监控 测试

_________________________________________________________________________________

测试。
启动LigServer,同时启动5个LigClient客户端。写完日志记客户端离线。观看消息变化。

1) Server已经成功的实现了对Client信息的监控。当客户端异常或正常离线,服务端对客户端实例资源进行移动操作

2) LigClient注册成功后,收到了来自LigServer的信息。。。

图 3.3.2  LigServer-LigClient双向通信 服务端监控

图 3.3.3  LigServer-LigClient双向通信 服务端监控

图 3.3.3  LigServer-LigClient双向通信 服务端监控 LigClient收来来自LigServer的信息

好了。到这里为止。Lig系统已经差不多满足我们的要求了。但还是不太完善,Lig系统还有上升的空间。我们前面说过,要优化LigClient使用的.等你看完

WCF 项目应用连载[4] - 自定义配置 扩展ServiceHost

WCF 项目应用连载[5] - 自定义配置 扩展ChannelFactory<T>  后,

WCF 项目应用连载[6] - 升级Lig服务 - 设计ILigger

将回答这一问题。

WCF 项目应用连载[6] - 升级Lig服务 - 设计ILigger以后。Lig工程将是一个比较完美的版本。

本节的源代码下载:

_________________________________________________________________________________

Litelog -WCF 项目应用连载[3] - 双向通信 并发 实例管理与服务端监控  源代码.rar

_________________________________________________________________________________

WCF 项目应用连载[4] - 自定义配置 扩展ServiceHost

参考引文:
[1] Artech.WCF全面解析[M].2012
[2] O'Reilly.WCF编程[M].2009
[3] Adnrew Trolesen.C#与.net3.5/4高级程序设计[M].2009/2013

WCF 项目应用连载[3] - 双向通信 实例管理与服务端监控的更多相关文章

  1. WCF 项目应用连载[2] - 创建Lig日志系统

    WCF 项目应用连载[1] - 索引 - 轻量级的Log系统 - Lig Sample -序 现在我们创建一个Lig工程 - Litelog 2.1 创建Lig服务 _________________ ...

  2. WCF 项目应用连载[8] - 绑定、服务、行为 大数据传输与限流 - 下 (ServiceThrottlingAttribute)

    因为ORM的原因,对Attribute编程有一种情节..所以这节的出现,完全是因为在WCF对自定义Attribute的一种应用. WCF 项目应用连载[7] - 绑定.服务.行为 大数据传输与限流 - ...

  3. 实例PK(Vue服务端渲染 VS Vue浏览器端渲染)

    Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司 ...

  4. “快的打车”创始人陈伟星的新项目招人啦,高薪急招Java服务端/Android/Ios 客户端研发工程师/ mysql DBA/ app市场推广专家,欢迎大家加入我们的团队! - V2EX

    "快的打车"创始人陈伟星的新项目招人啦,高薪急招Java服务端/Android/Ios 客户端研发工程师/ mysql DBA/ app市场推广专家,欢迎大家加入我们的团队! - ...

  5. loadrunner 编写socket脚本实例(附服务端实现)

    一.socket背景知识 这个咱就不废话了,网上一搜一大堆 二.本实例实现的功能 服务端接收客户端发送的字符串,并返回"5678succ"共8个字符 三.服务端实现(java代码) ...

  6. socket基础实例(一个服务端对应一个客户端情形)

    服务端处理1个客户端的例子 运行结果: (1) while(accept+if(recv)) 情形 执行服务端进程: [root@localhost single_link]# ./server [s ...

  7. pm2 工具来管理 node 服务端

    如下: nodeServer.js 'use strict'; const http = require('http'); const server = http.createServer(funct ...

  8. Netty实例-简单的服务端-client实现,凝视具体

           书籍推荐:                                       实例代码 :http://download.csdn.net/detail/jiangtao_st ...

  9. 一: WCF的服务端与客户端在通信时有三种模式:请求响应模式、数据报模式和双工通讯模式。

    说一下基本知识,  1.如果想要将当前接口作为wcf服务器,则一定要加上[ServiceContract] 契约 2.要想将方法作为wcf服务方法发布给外部调用,则一定要加上    [Operatio ...

随机推荐

  1. sicily-2499 平方数

    题目分析: 一个数可以表示成四种状态,所以可以用一个状态数组来存放该数由几个数的平方和表示.1.表示该数本身是完全平方.2.表示该数是由两个平方和3.表示三个.4.表示4个.一次遍历找出本身是完全平方 ...

  2. javascript——函数内部属性

    <script type="text/javascript"> //在函数内部有两个特殊的属性:arguments 和 this.arguments是一个类数组对象,包 ...

  3. Oauth认证简介

    Oauth是什么: 1.Oauth是一种安全认证的协议: 2.Oauth为用户资源的授权提供了一个安全的.开放而又简易的标准: 3.Oauth的授权不会使第三方触及到用户的账号信息(用户名和密码). ...

  4. jQuery慢慢啃之属性(三)

    1.attr(name|properties|key,value|fn)设置或返回被选元素的属性值. $("img").attr("src");//获取属性 $ ...

  5. amf0解释一下

    就简单记录一下省了以后忘了,amf0其实就几种数据格式的网络传输格式,比如数字,字符串,这些格式在传输的时候他给单独序列化了一下,主要支持以下这些: #define AMF0_NUMBER ((uin ...

  6. OS X Yosemite下安装Hadoop2.5.1伪分布式环境

    最近开始学习Hadoop,一直使用的是公司配好的环境.用了一段时间后发现对Hadoop还是一知半解,故决定动手在本机上安装一个供学习研究使用.正好自己用的是mac,所以没啥说的,直接安装. 总体流程 ...

  7. javascript获取div高度

    DOM的: 获得了div的高度值 = document.getElementById("目标id").offsetHeight;

  8. 熄灯问题 --POJ 2811-ACM

    问题描述 盏灯的状态. 列的灯的状态就不改变. 请你写一个程序,确定需要按下哪些按钮,恰好使得所有的灯都熄灭.根据上面的规则,我们知道: 次按下时所产生的结果.因此,每个按钮最多只需要按下一次: (2 ...

  9. bzoj1038: [ZJOI2008]瞭望塔

    Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, ...

  10. bzoj3637: Query on a tree VI

    Description You are given a tree (an acyclic undirected connected graph) with n nodes. The tree node ...