由于学习计划安排不当,对WCF的认知一直停滞不前,最近工作上又用回了WCF,重拾一下,看到蒋老师介绍双工通讯的博文,实践一下,积累一下。原想着WCF的双工通讯就是原本的客户端能调用服务端的方法之余,服务端同样也能调用客户端的方法。把博文看了一遍之后发现这个双工实际上是借助了方法回调实现的。那么下面先介绍一下最基本的双工通讯形式,再介绍一下鄙人利用双工通讯设计了一种形式。

  WCF通讯都是基于方法调用进行信息交互和传递,在开发基本模式的时候也需要往服务端下载元数据信息,从而让客户端知道服务端定义的方法签名,这就是契约;那么转到双工模式下,服务端调用客户端的方法,主调方也要知道方法的签名,这也是通过契约来实现,但是契约的定义并非在定义方法的客户端,仍然是在服务端,服务端定义了契约再由客户端下载了元数据后将其实现。

  下面则定义了一个契约,其目的让客户端往服务端发起连接,等待服务端的回调

     [ServiceContract(CallbackContract = typeof(ICallback))]
interface ILogic
{
[OperationContract]
void ListenToCall();
}

在ServiceContract特性中,使用了CallbackContract,表名了这个契约的回调契约就是ICallback。该回调契约也是自定义的一个接口

     [ServiceContract]
interface ICallback
{
[OperationContract]
List<int> GetHourMinuteFromClient();
}

它与普通模式定义的契约一样,就是一个单单纯纯的服务契约而已。但是在服务端想调用客户端的方法时,就是调用这个ICallback接口里面的方法,在这里就是GetHourMinuteFromClient()

在服务端需要实现ILogic接口来实现契约

     [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class LogicService:ILogic
{ public void ListenToCall()
{
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
callback.GetHourMinuteFromClient(); }
}

这里实现的方法就是回调客户端的GetHourMinuteFromClient()方法,它是利用OperationContext.Current.GetCallbackChannel 来获取一个实现ICallback的对象,通过该对象则调用指定的回调方法。另外一个就是在ServiceBehavior特性上给ConcurrencyMode属性赋上Reentrant或者Multiple,这样就免得在调用回调方法时出现死锁的异常。

在客户端下载了元数据信息后,就可以实现之前的回调契约,

     class ClassCallBack : ILogicCallback
{ public int[] GetHourMinuteFromClient()
{ int[] result= new List<int>() { DateTime.Now.Hour, DateTime.Now.Minute }.ToArray(); Console.WriteLine("{0},{1}",result[],result[]); return result;
}
}

不知这里是否与配置有关,鄙人在客户端获取到的接口名称是ILogicCallback,并非与蒋老师的Demo中一样——与服务端的ICallback接口同名。这里只是简单地输出了当前的小时和分钟,并作返回。

最后讲讲配置,能支持双工通讯的binding只有WSDualHttpBinding和NetTcpBinding(自定义的除外),我这里就用了NetTcpBinding。

 <system.serviceModel>
<services>
<service name="Logic.LogicService" behaviorConfiguration="te">
<host>
<baseAddresses>
<add baseAddress="net.tcp://127.0.0.1:8004/LogicService"/>
</baseAddresses>
</host>
<endpoint address="" binding="netTcpBinding" contract="Logic.ILogic" bindingConfiguration="transportNetTcpBinding"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="transportNetTcpBinding" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647">
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647"
maxNameTableCharCount="2147483647" maxStringContentLength="2147483647"/>
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="te">
<serviceMetadata httpGetEnabled="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

客户端的配置信息鄙人没有自己去写了,直接从服务引用那里粘贴生成的,就可以用得上。

 <system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_ILogic">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://127.0.0.1:8004/LogicService" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_ILogic" contract="Proxy.ILogic"
name="NetTcpBinding_ILogic" />
</client>
</system.serviceModel>

在客户端那里调用没有按照蒋老师说介绍的利用通道工厂来创建客户端对象,而是直接利用一个实现了ILogic接口的类来调用,那个类不是自己定义的,也是通过服务引用那里生成得来的。

         static void Main(string[] args)
{
InstanceContext context = new InstanceContext(new ClassCallBack());
LogicClient client = new LogicClient(context);
client.Open();
//using (client as IDisposable)
//{
client.ListenToCall();
//Console.ReadKey();
//}
Console.ReadKey();
}

蒋老师的博文上有用了using语句块的,但我这里没加上去也行,并没有抛异常,加了上去会更保险吧!

  那么鄙人在实际中遇到了这么一个情况,网络通讯已经采用了WCF框架,如果要换技术的话得大动干戈了,想要实现两个客户端之间的通讯,如果像使用Socket实现两个客户端之间直接通讯,那个还比较简单,但是用了WCF之后就比较麻烦了,客户端于客户端之间没法直接通讯,所有交互都是往服务端发请求,调用方法。那么只能使用WCF的双工通讯来实现了,WCF的服务端在整个结构而言就相当于一个中介者

这只是一个通讯的过程,在通讯之前的话肯定是每个客户端都连接一下服务端,让服务端记录了客户端的信息,当有客户端发出与别的客户端通讯的请求时,服务端就会查找出之前记录的信息,调用相应客户端的回调方法来实现。这个过程没分析过其资源的占用情况,但经过实践得出是可行的。

  基于上面的代码,契约里面则需要多增加一个方法,从而使得客户端能往服务端发送取数请求

     [ServiceContract(CallbackContract = typeof(ICallback))]
interface ILogic
{
[OperationContract]
void ListenToCall(); [OperationContract]
List<int> GetHourMinute ();
}

回调的契约不需要作改动,实现ILogic的类就改成这样

     [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class LogicService:ILogic
{
protected delegate List<int> callbackDelegate(); private static Dictionary<string, callbackDelegate> clientLst; protected static Dictionary<string, callbackDelegate> ClientLst
{
get
{
if (clientLst == null)
clientLst = new Dictionary<string, callbackDelegate>();
return clientLst;
}
} public void ListenToCall()
{
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
MessageProperties properties = OperationContext.Current.IncomingMessageProperties;
RemoteEndpointMessageProperty endpoint =
properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
ClientLst[endpoint.Address+endpoint.Port] = callback.GetHourMinuteFromClient; } public List<int> GetHourMinute ()
{
//return new List<int>() { DateTime.Now.Hour, DateTime.Now.Minute };
List<int> result= ClientLst.First().Value.Invoke(); return result;
}
}

ListenToCall的作用就是相当于客户端给服务端报个到,让服务端记录了客户端的IP地址端口号这些信息,还要把回调方法的委托记录下来,这些信息都存在了一个Dictionary<string, callbackDelegate> 的字典集中。在另一个方法GetHourMinute方法里面就负责按照指定的IP地址端口号来调用委托,这样就能调取指定客户端的方法了,不过上面的代码只是一个很基础很基础的示范,很多安全性的判断没加上去。

本篇博文就此结束了,关于那个客户端间接通讯的有什么意见和建议恳请大家多多提出,鄙人虚心接受,谢谢!

WCF双工通讯以及客户端间的间接通讯的更多相关文章

  1. 利用WCF双工模式实现即时通讯

    概述 WCF陆陆续续也用过多次,但每次都是浅尝辄止,以将够解决问题为王道,这几天稍闲,特寻了些资料看,昨晚尝试使用WCF的双工模式实现了一个简单的即时通讯程序,通过服务端转发实现客户端之间的通讯.这只 ...

  2. [SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端

    原文:[SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端 之前开发基于WinForm监控的软件,服务端基于Wcf实现,里面涉及双工模式,在客户端里面,采用心跳包机制保持与服 ...

  3. WCF双工学习笔记

    WCF双工的作用在于服务端执行某个方法的时候调用客户端的方法,有点类似委托的感觉,实际项目中在什么情况下使用还没想到. WCF双工支持两种bind,一是nettcp.另一个是wsDualHttp,这里 ...

  4. 一步步改造wcf,数据加密传输-匿名客户端加密传输

    一步步改造wcf,数据加密传输-匿名客户端加密传输 百度搜索wcf加密传输,资料挺多,真真正正能用的确不多. 一是本来就很复杂,而是各位大神给的资料不足.本人今天来提供一个简易方法. 匿名客户端加密传 ...

  5. 项目源码--Android即时通讯IM客户端

    下载源码   技术要点: 1.完整精美客户端UI设计 2.自定义控件的灵活使用 3.UI控件的详细使用 4.即时通讯IM协议的实现 5.完整即时通讯IM客户端实现 6.源码详细的中文注释 …….   ...

  6. 一个进程间同步和通讯的 C# 框架

    转自原文 一个进程间同步和通讯的 C# 框架 threadmsg_demo.zip ~ 41KB    下载 threadmsg_src.zip ~ 65KB    下载 0.背景简介 微软在 .NE ...

  7. 【解决】挂载NFS服务时,不同共享客户端间的数据不同步

    问题现象 当您用台 ECS 挂载同一个 NFS 文件系统,在 ECS-A 上 append 写文件,在 ECS-B 用 tail -f 观察文件内容的变化.在 ECS-A 写完之后,在 ECS-B 看 ...

  8. v76.01 鸿蒙内核源码分析(共享内存) | 进程间最快通讯方式 | 百篇博客分析OpenHarmony源码

    百篇博客分析|本篇为:(共享内存篇) | 进程间最快通讯方式 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) | 同样 ...

  9. 【工业串口和网络软件通讯平台(SuperIO)教程】一.通讯机制

    1.1    应用场景 通讯平台的交互对象包括两方面:第一.与硬件产品交互.第二.与软件产品交互.基本这两方面考虑,通讯平台一般会应用在两个场景: 1)通讯平台应用在PC机上 主要应用在自动站的工控机 ...

随机推荐

  1. 基础调试命令 - wt (watch and trace)

    本文介绍windbg动态调试过程中一个非常有用的命令,wt的用法. wt命令 wt命令之所以称为wt是因为它是watch and trace的简称,即用来观察和跟踪的命令.这个命令一般用在动态调试而不 ...

  2. Java面向对象思想解决猜拳问题

    第一个面向对象的程序: 一个控制台猜拳小游戏: 第一步选择角色: 第二部选择剪刀,石头,布,与电脑进行PK: 第三部选择继续或者选择结束; 结束显示比赛的局数,以及各自赢得的分数: 设计思路 分析问题 ...

  3. weinre使用

    2016-1-21 更新说明: 微信web开发者工具已经集成了weinre,只需设置手机代理便可调试任意页面,更简单更方便,推荐使用! Web应用开发者需要针对手机进行界面的调试,但是手机上并没有称心 ...

  4. js笔记——js里的null和undefined

    以下内容摘录自阮一峰的<语法概述 -- JavaScript 标准参考教程(alpha)>章节『5.null和undefined』,以做备忘. null与undefined都可以表示&qu ...

  5. javascript里阻止事件冒泡

    如下图所示,灰色块包含红色块,假设我们为灰色和红色块各绑定一个单击弹框事件,当我们点击红色块时,不希望触发灰色块的弹框事件,这就需要阻止冒泡事件了. IE里阻止冒泡事件使用cancelBubble属性 ...

  6. sql基础知识:分页+排序

    Oracle的分页还真是挺恶心地,不像mysql直接Limit就搞定 select name from student limit 0,20; Oracle需要借助rownum实现: select * ...

  7. css自适应宽高等腰梯形

    t1是梯形, ct是梯形里面的内容. 梯形的高度会随着内容的高度撑高.宽度随着浏览器窗口变宽. 梯形上窄下宽或上宽下窄可以通过 transform 的大小来修改. <div class=&quo ...

  8. JS脚本

    js脚本是嵌在网页里打出的一块区域,一般写在最下端 script   脚本 //      这是单行注释的一种语法 /**/  这是多行注释的一种语法 存储内容的东西叫变量 数据类型的有: 1  整型 ...

  9. salesforce 零基础开发入门学习(十四)salesforce中工厂模式的运用

    提到工厂模式,想必大家都很熟悉,工厂模式作为一种设计模式,同样在salesforce中适用. 举一个例子,笔作为基类,可以有钢笔,铅笔,圆珠笔等等.有一个笔的工厂,当你向它要钢笔,它就会生产一支钢笔; ...

  10. 移动端IM开发需要面对的技术问题

    1.前言 这两年多一直从事网易云信 iOS 端 IM SDK的开发,期间不断有兄弟部门的同事和合作伙伴过来问各种技术细节,干脆统一介绍下一个IM APP的方方面面,包括技术选型(包括通讯方式,网络连接 ...