WCF双工通讯以及客户端间的间接通讯
由于学习计划安排不当,对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双工通讯以及客户端间的间接通讯的更多相关文章
- 利用WCF双工模式实现即时通讯
概述 WCF陆陆续续也用过多次,但每次都是浅尝辄止,以将够解决问题为王道,这几天稍闲,特寻了些资料看,昨晚尝试使用WCF的双工模式实现了一个简单的即时通讯程序,通过服务端转发实现客户端之间的通讯.这只 ...
- [SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端
原文:[SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端 之前开发基于WinForm监控的软件,服务端基于Wcf实现,里面涉及双工模式,在客户端里面,采用心跳包机制保持与服 ...
- WCF双工学习笔记
WCF双工的作用在于服务端执行某个方法的时候调用客户端的方法,有点类似委托的感觉,实际项目中在什么情况下使用还没想到. WCF双工支持两种bind,一是nettcp.另一个是wsDualHttp,这里 ...
- 一步步改造wcf,数据加密传输-匿名客户端加密传输
一步步改造wcf,数据加密传输-匿名客户端加密传输 百度搜索wcf加密传输,资料挺多,真真正正能用的确不多. 一是本来就很复杂,而是各位大神给的资料不足.本人今天来提供一个简易方法. 匿名客户端加密传 ...
- 项目源码--Android即时通讯IM客户端
下载源码 技术要点: 1.完整精美客户端UI设计 2.自定义控件的灵活使用 3.UI控件的详细使用 4.即时通讯IM协议的实现 5.完整即时通讯IM客户端实现 6.源码详细的中文注释 ……. ...
- 一个进程间同步和通讯的 C# 框架
转自原文 一个进程间同步和通讯的 C# 框架 threadmsg_demo.zip ~ 41KB 下载 threadmsg_src.zip ~ 65KB 下载 0.背景简介 微软在 .NE ...
- 【解决】挂载NFS服务时,不同共享客户端间的数据不同步
问题现象 当您用台 ECS 挂载同一个 NFS 文件系统,在 ECS-A 上 append 写文件,在 ECS-B 用 tail -f 观察文件内容的变化.在 ECS-A 写完之后,在 ECS-B 看 ...
- v76.01 鸿蒙内核源码分析(共享内存) | 进程间最快通讯方式 | 百篇博客分析OpenHarmony源码
百篇博客分析|本篇为:(共享内存篇) | 进程间最快通讯方式 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) | 同样 ...
- 【工业串口和网络软件通讯平台(SuperIO)教程】一.通讯机制
1.1 应用场景 通讯平台的交互对象包括两方面:第一.与硬件产品交互.第二.与软件产品交互.基本这两方面考虑,通讯平台一般会应用在两个场景: 1)通讯平台应用在PC机上 主要应用在自动站的工控机 ...
随机推荐
- 【网站国际化必备】Asp.Net MVC 集成Paypal(贝宝)快速结账 支付接口 ,附源码demo
开篇先给大家讲段历史故事,博主是湖北襄阳人.襄阳物华天宝,人杰地灵,曾用名襄樊.在2800多年的历史文化中出现了一代名相诸葛亮(卧龙),三国名士庞统(凤雏),魏晋隐士司马徽(水镜先生),唐代大诗人孟浩 ...
- 使用ACE_Get_Opt解析命令行
当我们用C++开发一些C++控制台小工具时,会需要一些用户输入的参数来决定程序如何工作和执行,而用户输入参数的方式大部分都是采用命令行参数的方式. 比如上一篇文章 玩转Windows服务系列--命令行 ...
- HTML5文件上传插件 Huploadify V2.1发布
月初发布了HUploadify2.0版本,增加了文件的断点续传功能,得到了不少朋友的好评.本着按照Uploadify原样复制的原则,本次在一些朋友的建议中采纳了几点,做了一次较小的改动,定为2.1版本 ...
- 学习Scala02 基本类型
scala中有9大基本类型: Byte .Short .Int .Long. Char .String .Float. Double .Boolean 与java的基本类型看起来基本是一致的,但实际上 ...
- pydev+eclipse+python3.4运行hello word,提示Error in sitecustomize; set PYTHONVERBOSE for traceback:
刚开始学习python,按照网上步骤搭建好pydev+eclipse的开发环境,运行print("hello world")提示下面错误: Error in sitecustomi ...
- 《OOC》笔记(1)——C语言const、static和extern的用法
<OOC>笔记(1)——C语言const.static和extern的用法 C语言中const关键字用法不少,我只喜欢两种用法.一是用于修饰函数形参,二是用于修饰全局变量和局部变量. 用c ...
- Model模型和Module模块的区别
资料是从网上找的,具体是谁最先写的,不清楚了. Model通常是指模型.这个模型也许是你需求分析出来的, 也许是你算法做出来的. 不过最大可能是MVC的网站,或者是GUI开发模式中的M里的那个模型. ...
- struts2学习笔记之八:Action中方法的动态调用
方法一:action名称+!+方法名称+后缀 Action类中增加addUser()和delUser()方法, package com.djoker.struts2; import org.apach ...
- IOS开发之控件篇UICollectionViewControllor第一章 - 普通介绍
1.介绍 UICollectionView和UICollectionViewControllor是IOS6.0后引入的新控件 使用UICollectionView必须实现三个接口: UICollect ...
- KnockoutJS 3.X API 第四章 数据绑定(3) 控制流if绑定和ifnot绑定
if绑定目的 if绑定一般是格式是data-bind=if:attribute,if后所跟属性或表达式的值应为bool值(也可以是非bool值,当非空字符串时则为真),if绑定的作用与visible绑 ...