WCF双工通信

简介:

在WCF通信中,如果实现要得到服务端处理的结果,一种方式是在契约中指定调用方法带返回值(IsOneWay=false),但这种方式是有缺陷的,如果服务端处理时间过长,则客户端也需要长时间等待。
另一种方式是通过双工通信,使用回调来实现。但回调的时候,回调方法中不应该有耗时操作,否则当服务端处理完成退出的时间,回调消息会丢失。
目前WCF支持双工的绑定方式有:WSDualHttpBinding,NetTcpBinding与NetNamedPipeBinding三种,其它绑定方式不支持双工。
下面以一个简短的例子说明双工通信。
1、定义契约

[ServiceContract(Namespace = "http://cnblog.com/zhili/", CallbackContract = typeof(ICallback))]
    public interface ICalculator
    {
        [OperationContract(IsOneWay = true)]
        void Multiple(double a, double b);
        [OperationContract(IsOneWay = true)]
        void DisplayString(string name);
    }

其中指定了回调契约是ICallback。

// 回调契约的定义,此时回调契约不需要应用ServiceContractAttribute特性
    public interface ICallback
    {
        [OperationContract(IsOneWay = true)]
        void DisplayResult(double x, double y, double result);

        [OperationContract(IsOneWay = false, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
        string DisplayStringResult(string retStr);
    }

我们看到,回调第二个方法有返回值。这个在服务行为配置中要有特殊配置,否则会卡死。
2、服务端实现
实现服务契约:

 // 服务契约的实现
    [ServiceBehavior(IncludeExceptionDetailInFaults = true,ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class CalculatorService : ICalculator
    {
        #region ICalculator Members

        public void Multiple(double a, double b)
        {
            for (int i = 1; i < 100; i++)
            {
                double result = a * b;

                // 通过客户端实例通道
                ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();

                // 对客户端操作进行回调
                callback.DisplayResult(a, b, result);
                Console.WriteLine("Callback Times {0} at time {1}", i, DateTime.Now.ToString("hh:mm:ss tt zz"));
            }
            Program.ExitFlag = true;
        }

        public void DisplayString(string name)
        {
           
            for (int i = 1; i < 100; i++)
            {
                // 通过客户端实例通道
                ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
               
                // 对客户端操作进行回调
                string retStr = callback.DisplayStringResult("Hello " + name);
                Console.WriteLine("Callback Times {0} at time {1}, ret={2}", i, DateTime.Now.ToString("hh:mm:ss tt zz"), retStr);
            }
            Program.ExitFlag = true;
        }

        #endregion
    }

其中ServiceBehavior属性的ConcurrencyMode = ConcurrencyMode.Multiple配置就是配置回调方法带返回值问题(IsOneWay=false),如果不设置这个属性,或者设置为Single,上述回调方法调用时会卡死。
主程序如下:

 class Program
    {
        public static bool ExitFlag = false;
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
            {
                host.Opened += delegate
                {
                    Console.WriteLine("Service start now....");
                };

                host.Open();
                while (!ExitFlag)
                {
                    Thread.Sleep(500);
                }
            }
        }
    }

主程序配置(App.Config):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior>
                    <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8080/Metadata"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service name="NMS.WCFDemo.Server.CalculatorService">
                <endpoint address="net.tcp://localhost:9003/CalculatorService" binding="netTcpBinding" contract="NMS.WCFDemo.Contract.ICalculator"/>
            </service>
        </services>
    </system.serviceModel>
</configuration>

3、客户端
创建完客户端程序后,添加一个服务引用,指向上面配置文件的地址http://localhost:8080/Metadata获取服务引用。(添加服务引用时服务程序必须已经在运行)
实现回调契约:

// 客户端中对回调契约的实现
    public class CallbackWCFService : ICalculatorCallback
    {
        private int i = 1;
        public void DisplayResult(double a, double b, double result)
        {
            Console.WriteLine("{4}  :  {0} * {1} = {2}  ====== AT Time {3}", a, b, result, DateTime.Now.ToString("hh:mm:ss tt zz"), i++);
            Thread.Sleep(1000);
        }

        public string DisplayStringResult(string retStr)
        {
            Console.WriteLine("{0}  :  recevie msg  {1} ====== AT Time {2}", i++, retStr, DateTime.Now.ToString("hh:mm:ss tt zz"));
            Thread.Sleep(1000);
            return i.ToString();
        }
    }

客户端主程序:

// 客户端实现,测试回调操作
    class Program
    {
        static void Main(string[] args)
        {
            InstanceContext instanceContex = new InstanceContext(new CallbackWCFService());
            CalculatorClient proxy = new CalculatorClient(instanceContex);
            if (args[0] == "1")
            {
                proxy.Multiple(2, 3);
            }
            else
            {
                Console.WriteLine("Call string ...");
                proxy.DisplayString("Client");
            }
            Console.Read();
        }
    }

客户端配置文件(App.Config)

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_ICalculator" />
                <binding name="NetTcpBinding_ICalculator1" />
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://localhost:9003/CalculatorService"
                binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICalculator"
                contract="NMS.WCFDemo.Contract.ICalculator" name="NetTcpBinding_ICalculator" />
            <endpoint address="net.tcp://localhost:9003/CalculatorService"
                binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICalculator1"
                contract="ServiceReference1.ICalculator" name="NetTcpBinding_ICalculator1">
                <identity>
                    <userPrincipalName value="DESKTOP-4D9M16H\wangcc" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

然后运行程序就能看到效果了。

目录
相关文章
|
XML 网络协议 IDE
WCF基础教程(三)——WCF通信过程及配置文件解析
WCF基础教程(三)——WCF通信过程及配置文件解析
362 0
WCF基础教程(三)——WCF通信过程及配置文件解析
wcf双工通讯
首先说一个服务引用不成功的解决办法: 需要把服务端配置文件中的Binding换成: 或: 下面是一个wcf的简单示例: 服务契约代码: using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace WcfService { // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IUser”。
988 0
|
安全 网络协议 开发工具
WCF 通信接口
引用:http://baike.baidu.com/view/1140438.htm 概述   Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分,由 .NET Framework 3.0 开始引入,与 Windows Presentation Foundation及 Windows Workflow Foundation并行为新一代 Windows 操作系统以及 WinFX 的三个重大应用程序开发类库。
1178 0
|
消息中间件 测试技术 Windows
WCF 消息队列通信
MSMQ, microsoft Message Queue,微软消息队列。通过它,应用程序开发人员可以通过发送和接收消息,来与应用程序进行快速可靠的通信。   在WCF中,提供了MSMQ通信绑定:NetMsmqBinding和MsmqIntegrationBinding 这里做个简单的演示。
695 0