Wcf 双工通信的应用

2023-05-16

概述

双工(Duplex)模式的消息交换方式体现在消息交换过程中,参与的双方均可以向对方发送消息。基于双工MEP消息交换可以看成是多个基本模式下(比如请求-回复模式和单项模式)消息交换的组合。双工MEP又具有一些变体,比如典型的订阅-发布模式就可以看成是双工模式的一种表现形式。双工消息交换模式使服务端回调(Callback)客户端操作成为可能。

在Wcf中不是所有的绑定协议都支持回调操作,BasicHttpBinding,WSHttpBinding绑定协议不支持回调操作;NetTcpBinding和NetNamedPipeBinding绑定支持回调操作;WSDualHttpBinding绑定是通过设置两个HTTP信道来支持双向通信,所以它也支持回调操作。

两种典型的双工MEP

1.请求过程中的回调

这是一种比较典型的双工消息交换模式的表现形式,客户端在进行服务调用的时候,附加上一个回调对象;服务在对处理该处理中,通过客户端附加的回调对象(实际上是调用回调服务的代理对象)回调客户端的操作(该操作在客户端执行)。整个消息交换的过程实际上由两个基本的消息交换构成,其一是客户端正常的服务请求,其二则是服务端对客户端的回调。两者可以采用请求-回复模式,也可以采用单向(One-way)的MEP进行消息交换。下描述了这样的过程,服务调用和回调都采用请求-回复MEP。

1

2.订阅-发布

订阅-发布模式是双工模式的一个典型的变体。在这个模式下,消息交换的双方变成了订阅者和发布者,若干订阅者就某个主题向发布者申请订阅,发布者将所有的订阅者保存在一个订阅者列表中,在某个时刻将主题发送给该主题的所有订阅者。实际上基于订阅-发布模式的消息交换也可以看成是两个基本模式下消息交换的组合,申请订阅是一个单向模式的消息交换(如果订阅者行为得到订阅的回馈,该消息交换也可以采用请求-回复模式);而主题发布也是一个基于单向模式的消息交换过程。订阅-发布消息交换模式如下所示。

2

示例

接下来我们将会创建一个简单的Wcf通信服务,包括使使用NetTcpBinding实现双工通信,和监控双工通信过程中的客户端和服务端一方断开后的捕捉事件。

项目如图所示

image

第一步:

先创建IGateWayService和INotifyCallBack接口

  [ServiceContract(CallbackContract = typeof(INotifyCallBack))]
    public interface IGateWayService
    {
        [OperationContract]
        void RegisterClient(string clientName);
        [OperationContract]
        string GetData(int value);

        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);
    }


    // 使用下面示例中说明的数据约定将复合类型添加到服务操作。
    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }

 

 

INotifyCallBack.cs如下:

    public interface INotifyCallBack
    {
        [OperationContract(IsOneWay = true)]
        void NotifyFunction(string sender);
    }

 

记住在IGateWayService接口上方设置Attribute [ServiceContract(CallbackContract = typeof(INotifyCallBack))] 这样设置表示这个接口是支持回调的。

接下来定义一个ClientRegisterInfo.cs来定义客户端的名字和客户端的INotifyCallBack属性,再定义一个Timer 来调用INotifyCallBack给客户端发送消息。再通过

wcf 的ICommunicationObject来定义通信出错和关闭的事件。

 public class ClientRegisterInfo
    {
        public ClientRegisterInfo()
        {
            _senderTimer.Elapsed += OnSenderMessage;
            _senderTimer.Start();
        }

        private void OnSenderMessage(object sender, ElapsedEventArgs e)
        {
            if (_notifyCallBack != null)
            {
                 var communication = _notifyCallBack as ICommunicationObject;
                if(communication.State==CommunicationState.Opened)
                    _notifyCallBack.NotifyFunction(DateTime.Now.ToString());
            }
        }

        public Timer _senderTimer=new Timer(10*1000);

        private INotifyCallBack _notifyCallBack;

        public INotifyCallBack NotifyCallBack
        {
            get { return _notifyCallBack; }
            set
            {
                lock (_syncNotifyObj)
                {
                    _notifyCallBack = value;
                    if (_notifyCallBack != null)
                    {
                        var communication = _notifyCallBack as ICommunicationObject;
                        if (communication != null)
                        {
                            communication.Closed += OnChannelClose;
                            communication.Faulted += OnChannelFault;
                        }
                    }
                }
            }
        }

        private readonly object _syncNotifyObj = new object();

        private void OnChannelFault(object sender, EventArgs e)
        {
     
            ClientInfoCache.Instance.Remove(this);
        }

        private void OnChannelClose(object sender, EventArgs e)
        {
  
            ClientInfoCache.Instance.Remove(this);
        }

        public string ClientName { get; set; }
    }

 

再定义一个单例来保存客户端的信息。

 public class ClientInfoCache
    {
        private static readonly object SyncObj = new object();

        private static ClientInfoCache _instance;

        public static ClientInfoCache Instance
        {
            get
            {
                lock (SyncObj)
                {
                    if (_instance == null)
                        _instance = new ClientInfoCache();
                }
                return _instance;
            }
        }

        private ClientInfoCache()
        {
            _clientList = new List<ClientRegisterInfo>();
        }

        private List<ClientRegisterInfo> _clientList;

        private static object SyncOperator = new object();

        /// <summary>
        /// Add client entity
        /// </summary>
        /// <param name="entity">client entity</param>
        public void Add(ClientRegisterInfo entity)
        {
            if (entity == null) return;
            lock (SyncOperator)
            {
                var findClient =
                    _clientList.FirstOrDefault(
                        t => t.ClientName.Equals(entity.ClientName, StringComparison.OrdinalIgnoreCase));
                if (findClient == null)
                    _clientList.Add(entity);
                else
                {
                    findClient.NotifyCallBack = entity.NotifyCallBack;
                }
            }
        }

        /// <summary>
        /// Remove client
        /// </summary>
        /// <param name="entity">Client entity</param>
        public void Remove(ClientRegisterInfo entity)
        {
            lock (SyncOperator)
            {
                _clientList.Remove(entity);
            }
        }
    }

 

再新建个控制台运应程序来启动Wcf,代码如下:

 public class Program
    {
        static void Main(string[] args)
        {
            StartListener();
        }

        private static void StartListener()
        {
            try
            {
                using (var host = new ServiceHost(typeof(GateWayService)))
                {
                    host.Opened += delegate
                    {
                        Console.WriteLine("[Server] Begins to listen request on " + host.BaseAddresses[0]);
                    };

                    host.Open();
                    Console.Read();
                }
            }
            catch (Exception ex)
            {
             
            }
        }
    }

 

在App.config设置配置如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="longTimeoutBinding" closeTimeout="01:10:00" openTimeout="01:10:00"
 receiveTimeout="10:10:00" sendTimeout="10:10:00" maxBufferPoolSize="655350000"
 maxBufferSize="655350000" maxReceivedMessageSize="655350000">
          <readerQuotas maxDepth="32" maxStringContentLength="655350000"
            maxArrayLength="655350000" maxBytesPerRead="655350000" maxNameTableCharCount="655350000" />
          <reliableSession inactivityTimeout="23:59:59" />
          <security mode="None" />
        </binding>
      </netTcpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="NewBehavior">
          <serviceMetadata httpGetEnabled="True" httpGetUrl="Http://localhost:7789/" httpsGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
          <serviceThrottling maxConcurrentCalls="1000"  maxConcurrentSessions="1000"  maxConcurrentInstances="1000" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="WcfService.GateWayService" behaviorConfiguration="NewBehavior" >
        <endpoint  address="net.tcp://localhost:7788/GatewayService.svc"  binding="netTcpBinding"  contract="WcfService.IGateWayService" name="WcfService_GateWayService"  bindingConfiguration="longTimeoutBinding" >
        </endpoint>
        <endpoint  address="mex" binding="mexTcpBinding"   contract="IMetadataExchange" ></endpoint>
        <host >
          <baseAddresses >
            <add baseAddress="net.tcp://localhost:7788/GatewayService.svc" />
            <add baseAddress="Http://localhost:7789/" />
          </baseAddresses>
        </host >
      </service>
    </services>
  </system.serviceModel>
</configuration>

 

longTimeoutBinding是设置传输的属性,如最大传输大小,TimeOut的时间等。

在客户端新建个WcfCallBack.cs 继承IGateWayServiceCallback接口,代码如下。

 [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class WcfCallBack : IGateWayServiceCallback
    {
        public void NotifyFunction(string sender)
        {
            Console.WriteLine("Get a message,message info is {0}", sender);
        }
    }

 

 

设置属性[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]表示服务器是通过并发的给客户端来发送消息的。

控制台代码如下

 class Program
    {
        private static GateWayServiceClient _client;
        static void Main(string[] args)
        {
            var cb = new WcfCallBack();
            var context = new InstanceContext(cb);
            _client = new GateWayServiceClient(context);
            _client.RegisterClient("Test1");
            ((ICommunicationObject)_client).Closed += OnChannelClose;
            ((ICommunicationObject)_client).Faulted += OnChannelFaulted;
            Console.WriteLine("Input Q to exit.");
            while (string.Compare(Console.ReadLine(), ConsoleKey.Q.ToString(), StringComparison.OrdinalIgnoreCase) != 0)
            {

            }
        }

        private static  void OnChannelFaulted(object sender, EventArgs e)
        {
            if (FaultedEvent != null)
                FaultedEvent(sender, e);
        }

        private static  void OnChannelClose(object sender, EventArgs e)
        {
            if (CloseEvent != null)
                CloseEvent(sender, e);
        }

        public static  EventHandler CloseEvent;

        public static  EventHandler FaultedEvent;
    }

 

运行的结果如下图:

image

当我关闭客户端时,能捕捉到Closed和Faulted事件

image

 

当我关闭服务端时,在客户端能捕捉到Faulted事件

image

 

总结:

Wcf 通信使用简单,功能丰富。

转载于:https://www.cnblogs.com/springyangwc/p/3460178.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Wcf 双工通信的应用 的相关文章

随机推荐

  • 如何使用linux程序mdadm创建软件RAID1软阵列

    如何使用linux程序mdadm创建软件RAID1软阵列 磁盘冗余阵列 RAID 是将多个物理磁盘结合成一个逻辑磁盘的技术 xff0c 该技术可以提高磁盘容错性能 xff0c 提高磁盘的读写速度 根据数据存储的排列 如 xff1a 条带存储
  • 极乐净土----Android实现图片转ascii码字符图的一些尝试

    掘金第一篇 xff0c 先转一个自己以前的帖子吧 xff0c 懒得重新写了 www jianshu com p 357af674a 转载于 https juejin im post 5c36df2cf265da616624abc6
  • idea中使用FindBugs-IDEA插件

    下载 安装 重启idea即可 xff1b 项目右键或者文件右键即可看到 FindBugs 选项 选择某个选项直接检测即可 检测结果如下图 xff1a 这里的Correctness是重点关注对象 这里面的错误往往是比较严重的 像空指针之类的错
  • pip,virtualenv,conda和anaconda的个人理解

    1 pip pip是python下的包管理工具 xff0c 主要用于从pypi下载所需的python包 xff0c 但是pip不会自动处理包之间的依赖关系 xff1b 在使用pip安装包时 xff0c 可以修改安装源为https pypi
  • Windows Server 2016-Hyper-V网络虚拟化概述

    在 Windows Server 2016 和虚拟机管理器中 xff0c Microsoft 提供的端到端网络虚拟化解决方案 有构成了 Microsoft 的网络虚拟化解决方案的五个主要组件 xff1a Windows Azure Wind
  • mac环境下安装pysvn

    可以从下载页下载对应版本的pysvn xff1a https pysvn sourceforge io downloads html 之后双击打开安装即可 xff0c 不需要再用pip安装 需要注意的是 xff0c 如果安装时提示chdir
  • 关于PHP中Session文件过多的问题

    PHP的默认机制 xff1a 每一次php请求 xff0c 会有1 100的概率 xff08 默认值 xff09 触发 session回收 如果 session回收 发生 xff0c 那就会检查 tmp sess 的文件 xff0c 如果最
  • RDO 远程 桌面无法复制

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 这里是列表文本这里是列表文本首先我们要检查 登录机在进程管理器中是否有rdpclipe exe这个进程 如果有则杀掉 xff0c 如果没有 xff0c 则在任务管理器中菜单
  • 如何在 Excel 中自定义菜单和菜单栏

    Microsoft 提供的编程示例只用于说明目的 xff0c 不附带任何明示或默示的保证 这包括但不限于对适销性或特定用途适用性的默示保证 本文假定您熟悉所演示的编程语言和用于创建和调试过程的工具 Microsoft 的支持工程师可以帮助解
  • 轮环(Ouroboros)世界观介绍,摘自Guide Book

    基于现实的架空世界观 这个游戏的世界观是基于以现代人的眼光来看待自身长久以来的发展与盛衰交替的事实 xff0c 而在此基础上构想出的简化的因果逻辑 xff0c 以及其外在的表现形式 祭祀 游戏根据中国古代的以国家为单位的大规模殉 祭奴隶的事
  • css背景图等比例缩放,盒子随背景图等比例缩放

    很多时候我们给网站了一个大banner 但是随着屏幕的变化 xff0c 背景会变形 xff0c 我们知道background size可以实现背景图等比例缩放 xff0c 但是 xff0c 我们想让下面的盒子根据缩放后背景图的高度 xff0
  • 如何用PS快速的批量制作连续号码数字编号图解

    如何用PS快速的批量制作连续号码数字编号图解 大家好 xff0c 今天太原博飞设计培训小编就告诉大家如用 PS 快速的制作连续数字编号 xff0c 在工作中尤其是大型活动的有时候制作连续的号码牌 xff0c 少还好 xff0c 如果上百上千
  • 我们评测了5个主流跨端框架,这是它们的区别

    最近前端届多端框架频出 xff0c 相信很多有代码多端运行需求的开发者都会产生一些疑惑 xff1a 这些框架都有什么优缺点 xff1f 到底应该用哪个 xff1f 作为 Taro 开发团队一员 xff0c 笔者想在本文尽量站在一个客观公正的
  • 大牛直播SDK-Windows RTMP/RTSP/本地FLV播放器使用说明 ...

    大牛直播播放器SDK相对推送SDK来说 xff0c 接口没有那么多 xff0c 不过客户95 以上的常规需求均已覆盖 xff0c 目前支持RTMP和RTSP直播播放 xff0c 还有本地flv文件回放 xff1a 大牛直播SDK播放端提供C
  • 交换机的配置文件备份到TFTP和FTP服务器

    1 构建拓扑 2 配置地址 Switch gt Switch gt en Switch conf t Switch config hostname 666 修改交换机名字 666 config interface vlan 1 进入虚拟接口
  • 推荐几款常用的Socks5代理软件

    一 Sockscap 荐 SocksCap是目前对网络游戏兼容性最好的代理工具之一 SocksCap32 软件是由美国 NEC USA Inc 公司出品的代理服务器第三方支持软件 拥有功能强大的 SOCKS 调度 xff0c 使用它就可以让
  • Nginx根据post参数转发请求 (OpenResty)

    最近有个需求 xff0c 需要nginx根据POST参数将请求转发到不同的后端 xff0c 调研后决定使用OpenResty xff08 Nginx 43 Lua xff09 作为代理服务器 写个小Demo location span cl
  • Windows 10访问共享时提示“过时的SMB1协议”的修复办法

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 公司有台Windows XP老版本系统的文件共享服务器 xff0c 前段时间好好的能正常访问 xff0c 今天访问时突然提示 因为文件共享不安全 xff0c 所以你不能连接
  • 关于Video Src 带有 blob:http的视频如何下载的问题

    我们如果使用爬虫 xff0c 想爬取一些视频的时候 xff0c 会发现一些网站提供的视频链接打开是 404 xff1b span class hljs tag lt span class hljs name video span span
  • Wcf 双工通信的应用

    概述 双工 xff08 Duplex xff09 模式的消息交换方式体现在消息交换过程中 xff0c 参与的双方均可以向对方发送消息 基于双工MEP消息交换可以看成是多个基本模式下 xff08 比如请求 回复模式和单项模式 xff09 消息