WCF分布式开发步步为赢(4):WCF服务可靠性传输配置与编程开发

今天继续WCF分布式开发步步为赢系列的第4节:WCF服务可靠性传输配置与编程开发。这个章节,我们要介绍什么是WCF服务的可靠性传输,随便介绍网络协议的概念,Web Service为什么不支持可靠性传出,具体的WCF绑定协议和可靠性的关系,实现可靠性传输有什么方式,以及配置和开发的详细实现代码分析部分。【1】可靠性传输【2】配置方式实现可靠性传输【3】编程方式实现可靠性传输【4】编程实现必备有序传递【5】结果分析和总结。

    下面进入正式的内容:

 【1】可靠性传输:

【1.0】网络协议基础知识:

    这里我们有必要先介绍OSI参考模型几个主要协议的基本概念,见下表:

OSI中的层

功能

TCP/IP协议族

应用层

文件传输,电子邮件,文件服务,虚拟终端

TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet

表示层

数据格式化,代码转换,数据加密

没有协议

会话层

解除或建立与别的接点的联系

没有协议

传输层

提供端对端的接口

TCP,UDP

网络层

为数据包选择路由

IP,ICMP,RIP,OSPF,BGP,IGMP

数据链路层

传输有地址的帧以及错误检测功能

SLIP,CSLIP,PPP,ARP,RARP,MTU

物理层

以二进制数据形式在物理媒体上传输数据

ISO2110,IEEE802。IEEE802.2

     TCP/IP是一个协议族,为了帮助大家理解下面协议绑定的内容,把IP想像成一种高速公路,它允许其它协议在上面行驶并找到到其它电脑的出口。TCP和UDP是高速公路上的汽车,汽车上货物就是HTTP,SNMP,FTP,SMTP,DNS,Telnet 协议等。

  TCP和UDP是FTP,HTTP和SMTP等应用层协议使用的传输层协议。TCP提供面向连接、有保证的数据传输,而UDP不提供。TCP有一个特殊的机制来确保数据安全的不出错的从一个端点传到另一个端点,而UDP不提供任何这样的保证。

  HTTP(超文本传输协议)是利用TCP协议在两台机器(通常是Web服务器和客户端)之间传输信息的协议。客户端使用Web浏览器发起HTTP请求给Web服务器,Web服务器发送被请求的信息给客户端。

    这里随便介绍一下SOAP协议,它也是基于XML语言,可以实现分布式系统间的数据交换的协议。 SOAP:Simple Object Access Protocol简单对象访问协议是一种轻量的、简单的、基于 XML 的协议,它被设计成在 WEB 上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议( HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。它还支持从消息系统到远程过程调用(RPC)等大量的应用程序,当然也可以映射到TCP协议。

【1.1】WCF可靠性传输简介:

WCF与其他面向服务技术之间(asp.net /j2ee Web Service技术等)最大的区别在于传输可靠性(Transport Reliability)与消息可靠性(Message Reliability)。传输可靠性(例如通过TCP传输)在网络数据包层提供了点对点保证传递(Point-to-Point Guaranteed Delivery),以确保数据包的顺序无误。传输可靠性不会受到网络连接的中断或其他通信问题的影响。消息可靠性提供了端对端保证传递(End-to-End Guaranteed Delivery),确保消息的顺序无误。消息可靠性与引入的中间方的数量无关,与网络跳数(Network Hops)的数量也没有关联。消息可靠性基于一个行业标准。该行业标准为可靠的基于消息的通信维持了一个在传输层的会话。如果传输失败,例如无线连接中断,消息可靠性就会重试(Retries)功能。它还能够自动处理网络阻塞(Congestion)、消息缓存(Message Buffering)以及流控制(Flow Control),根据具体情况适时调整发送的消息数。消息可靠性还能够通过对连接的验证管理连接自身,并在不需要连接时清除它们。

 这里WCF的可靠性传输首先来说数据传输同样依赖底层的网络传输协议,如TCP协议,TCP传输控制协议底层就是要求建立连接的状态进行数据传递。其次消息可靠性也是对已有消息可靠性行业标准的支持,WCF框架实现或者扩展了消息可靠性行业标准。

Web Service使用http/post/get/soap三种方式进行访问,http协议是请求/响应协议,不会维持特定的传输通道,本身是不支持可靠性。

【1.2】传输协议与可靠性:

看来以上的介绍内容,我们再来介绍WCF绑定协议的可靠性,同样WCF的可靠性和具体的绑定协议弥补可分。总结了绑定、可靠性、有序传递(Ordered Delivery)以及它们各自的默认值之间的关系。可靠性与绑定对应关系如下:

可靠性与绑定对应关系

绑定协议名称            支持可靠性         默认可靠性           支持有序传递       默认有序传递

BasicHttpBinding                No               N/A                    No                  N/A

NetTcpBinding                   Yes               Off                    Yes                  On

NetPeerTcpBinding              No                N/A                   No                  N/A

NetNamedPipeBinding          No                N/A (On)           Yes                  N/A (On)

WSHttpBinding                  Yes               Off                    Yes                  On

WSFederationHttpBinding   Yes               Off                     Yes                  On

WSDualHttpBinding            Yes               On                     Yes                  On

NetMsmqBinding                 No                N/A                    No                   N/A

MsmqIntegrationBinding       No               N/A                    No                   N/A

BasicHttpBinding不支持可靠性,BasicHttpBinding面向旧的ASMX Web服务,是不具有可靠性的;

NetMsmqBinding不支持可靠性,MSMQ协议,使用消息队列,针对断开调用,不存在传输会话;              

MsmqIntegrationBinding不支持可靠性;支持WCF与MSMQ协议通信,不存在传输会话;

NetPeerTcpBinding不支持可靠性。NetPeerTcpBinding则为广播场景设计。

WSDualHttpBinding支持可靠性的,建立两个http会话通道,保持回调通道,确保基于HTTP协议的客户端存在;

NetTcpBinding 支持可靠性,显然使用TCP传输数据。以及各种WS绑定,默认情况下并不支持可靠性,允许启用;     

NetNamedPipeBinding绑定总是拥有一个确定的从客户端到服务的跳数,因而它的可靠性是绑定固有的;

WSFederationHttpBinding支持可靠性,支持联邦通信协议,支持在多个安全区域进行安全会话。

WS绑定协议一般都提供了对可靠性传递的支持,可以编程或者配置方式在项目里启用。可靠性传输要根据绑定的目标场景而定。

【1.3】有序消息:

     TCP提供了差错和流量控制。WCF消息可靠性也以来具体的绑定协议底层的传输协议和自身扩展的机制确保了消息的有序传递,允许消息按照发送顺序而非接收顺序执行。我们在实际的WCF项目里及可以只启用可靠性,而不启用有序传递。

    同样WCF也为我们提供了灵活的方式来配置也启用项目中的传输可靠性和传递的有序性,你可以使用配置文件方式也可以使用编程方式实现。如果我们启用了可靠性,则客户端与服务端必须保持配置一致,否则客户端无法与服务通信。我们可以只对支持它的绑定配置可靠性。下面我们就来进行详细的介绍。

【2】配置方式实现可靠性传输:

     下面我们使用服务端配置文件,启用了TCP绑定的可靠性。代码如下:

复制代码
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="WCFService.WCFServiceBehavior"
        name="WCFService.WCFService">
        <endpoint
          address="http://localhost:8001/WCFService"
          binding="wsHttpBinding"
          contract="WCFService.IWCFService">
        </endpoint>
        <endpoint
          address="net.tcp://localhost:8002/WCFService"
          binding="netTcpBinding"
           bindingConfiguration="ReliableTCP"
          contract="WCFService.IWCFService">
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8001/"/>
            <add baseAddress="net.tcp://localhost:8002/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="WCFService.WCFServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding >
        <binding name="ReliableTCP">
          <reliableSession enabled="True"/>
        </binding>
      </netTcpBinding>
    </bindings>
  </system.serviceModel>
复制代码

 这里我们要设置服务终结点的绑定配置,bindingConfiguration="ReliableTCP",然后在给出具体绑定配置的可靠传输

      <netTcpBinding >
        <binding name="ReliableTCP">
          <reliableSession enabled="True"/>
        </binding>
      </netTcpBinding>

这样WCF服务就会启用可靠消息传递。

【3】编程方式实现可靠性传输:

    至于编程配置方式,这里我们稍作介绍,TCP绑定和WS绑定提供了略微不同的属性来配置可靠性。这里的例子我们继续使用的是针对TCP编程实现可靠性传输的示例代码:

复制代码
//采用自托管方式,也可以是IIS、WAS,Windows服务等用户自定义程序托管服务
    public class WCFHost
    {
        static void Main(string[] args)
        {

            //反射方式创建服务实例,
            //Using方式生命实例,可以在对象生命周期结束时候,释放非托管资源
            using (ServiceHost host = new ServiceHost(typeof(WCFService.WCFService)))
            {
                //相同的服务注册多个基地址
                //添加服务和URI,用户资源标识符
                Uri tcpAddress = new Uri("net.tcp://localhost:8001/WCFService");
                //Uri httpAddress = new Uri("http://localhost:8002/WCFService");
                //Uri pipeAddress = new Uri("net.pipe://localhost:8002/WCFService");
                SecurityMode securityMode = new SecurityMode();//实例化安全模型
                //设置可靠性会话为真
                NetTcpBinding netTcpBinding = new NetTcpBinding(securityMode, true);
                //添加服务终结点,方式不变
                host.AddServiceEndpoint(typeof(WCFService.IWCFService), netTcpBinding, tcpAddress);
                //host.AddServiceEndpoint(typeof(WCFService.IWCFService), new WSHttpBinding(), httpAddress);
                //host.AddServiceEndpoint(typeof(WCFService.IWCFService), new NetNamedPipeBinding(), pipeAddress);
                ////判断是否以及打开连接,如果尚未打开,就打开侦听端口
                if (host.State != CommunicationState.Opening)
                    host.Open();
                //显示运行状态
                Console.WriteLine("Host is runing! and state is {0}", host.State);
                //等待输入即停止服务
                Console.Read();


            }
        }
复制代码

   SecurityMode securityMode = new SecurityMode();这个语句就是实例化安全模型,NetTcpBinding netTcpBinding = new NetTcpBinding(securityMode, true);传入的参数为true,就是启用可靠性传递。添加服务终结点,方式不变host.AddServiceEndpoint(typeof(WCFService.IWCFService), netTcpBinding, tcpAddress);这样就编程实现了TCP消息的可靠性传递。

【4】编程实现必备有序传递:

我们这里在简单介绍一下WCF有序传递的概念。我们知道服务代码和契约定义应该与它使用的绑定及属性无关。实际上,WCF服务的实现或者数据契约本身都会依赖于系统消息的有序传递(Ordered Delivery)。为了帮助契约或服务的开发者能够约束支持的绑定,WCF定义了DeliveryRequirementsAttribute类,这是一个密封类,不可继承,我们使用他来定义服务的传递属性。这里应用到服务属性,设置服务启用有序队列传递。

复制代码
    [DeliveryRequirementsAttribute(
  QueuedDeliveryRequirements = QueuedDeliveryRequirementsMode.Allowed,
  RequireOrderedDelivery = true
)]
    public class WCFService : IWCFService
    {
        //实现接口定义的方法
        public string SayHello(string name)
        {
            Console.WriteLine("Hello! {0},Using string ", name);
            return "Hello! " + name;
        }
        //实现接口定义的方法
        public string SayHelloToUser(User user)
        {
            Console.WriteLine("Hello! {0}    {1},Using DataContract ", user.FirstName, user.LastName);
            return "Hello! " + user.FirstName + " " + user.LastName;
        }
    }
复制代码

DeliveryRequirementsAttribute..::.RequireOrderedDelivery 属性设置绑定协议是否必须支持已排序消息。可以应用到服务一级,对WCF服务的所有终结点施加影响,或者只对公开了特定服务契约的终结点施加影响;如果应用到WCF服务一级,则意味着选用有序传递是根据具体实现作出的决策。DeliveryRequirements特性也可以应用到服务契约一级,它会对所有支持该契约的服务施加影响。体现了对有序传递的要求是根据设计作出的决策。这一约束会在装载服务时得到执行与验证。命名管道绑定符合有序传递的约束。注:

命名空间:  System.ServiceModel
程序集:  System.ServiceModel(在 System.ServiceModel.dll 中)

【5】结果分析和总结。

     配置完毕后,我们可以在客户端添加WCF服务引用,生成的配置文件,内容包含对可靠消息传递的配置信息,具体如下:

复制代码
            <netTcpBinding>
                <binding name="NetTcpBinding_IWCFService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
                    hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                    maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                    maxReceivedMessageSize="65536">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="true" />
                    <security mode="Transport">
                        <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </netTcpBinding>
复制代码

    <reliableSession ordered="true" inactivityTimeout="00:10:00"  enabled="true" />是对可靠消息传递的的设置节点信息。

   以上就是本节的全部内容,介绍了基本的网络协议,WCF可靠性传递的概念以及和具体的各个绑定协议之间的关系,我们还给出了一个简单的通过配置文件和代码实现可靠消息传递的例子。并进行了分析讲解。WCF为我们提供了可靠消息传递的有效机制,这个特性也是基于已有网络传输协议,WCF再次基础上多数据通信模型进行了扩展。这种特性确实对增强我们程序的数据传递的准确性有很大的帮助,但是是否使用可靠消息传递要基于实际的项目需要,不能强制使用。我们获得安全可靠性的同时,实际底层付出的是效率的代码。 下面是本节的示例代码/Files/frank_xl/WCFServiceReliableFrankXuLei.rar

供大家参考~下一节我们学习服务契约相关的知识点,敬请关注,谢谢。

参考:

1.百度百科:TCP/IP协议

2.《programming WCF Service》

3.msdn

原文地址:https://www.cnblogs.com/GoogleGetZ/p/5752534.html