由于学习计划安排不当,对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. html5 css3实现图中结构

    <!DOCTYPE html> <html lang="en" > <head> <title>demo</title> ...

  2. Linux split拆分文件

    200 ? "200px" : this.width)!important;} --> 介绍 split可以将一个大文件拆分成指定大小的多个文件,并且拆分速度非常的快,拆分一 ...

  3. mac下apache配置,解决It is not safe to rely on the system's timezone settings.

    之前一直转windows平台下做php,很少遇到问题.现在有了macbook,还在慢慢的熟悉中,搭建php开发环境,熟悉mac系统文档组织还有命令,颇费功夫. 今天我在mac下做一个php的练习,用到 ...

  4. Android中pullToRefresh使用

    pullToRefresh的导入 首先,点击new按钮 -> import Module 然后在 New Module界面选择已经在本地的含有源代码的pullToRefresh. 打开如下图所示 ...

  5. JSONP浅析

    DEMO : JSONP示例 为什么使用JSONP JSONP和JSON是不一样的.JSON(JavaScript Object Notation)是一种基于文本的数据交换方式,或者叫做数据描述格式. ...

  6. Java线程:线程状态的转换

    Java线程:线程状态的转换   一.线程状态   线程的状态转换是线程控制的基础.线程状态总的可分为五大状态:分别是生.死.可运行.运行.等待/阻塞.用一个图来描述如下:   1.新状态:线程对象已 ...

  7. Atitit sql执行计划

    Atitit sql执行计划 1.1. 首先要搞明白什么叫执行计划? 执行计划是数据库根据SQL语句和相关表的统计信息作出的一个查询方案,这个方案是由查询优化器自动分析产生的 Oracle中的执行计划 ...

  8. Java EE开发平台随手记1

    过完春节以来,一直在负责搭建公司的新Java EE开发平台,所谓新平台,其实并不是什么新技术,不过是将目前业界较为流行的框架整合在一起,做一些简单的封装和扩展,让开发人员更加易用. 和之前负责具体的项 ...

  9. java中父类与子类, 不同的两个类中的因为构造函数由于递归调用导致栈溢出问题

    /* 对于类中对成员变量的初始化和代码块中的代码全部都挪到了构造函数中, 并且是按照java源文件的初始化顺序依次对成员变量进行初始化的,而原构造函数中的代码则移到了构造函数的最后执行 */ impo ...

  10. 总结整理 -- python系列

    python系列 python--基础学习(一)开发环境搭建,体验HelloWorld python--基础学习(二)判断 .循环.定义函数.继承.调用 python--基础学习(三)字符串单引号.双 ...