WCF 项目应用连载[7] - 绑定、服务、行为 大数据传输与限流 - 上


上一节,我们说到WCF配置,谈到我们还欠一个对App.config的另外一个解释。。

这节以WCF服务端的配置说明App.config中出现参数的功能。我们要说明的这些参数主要含:


服务节点参数、行为节点参数、绑定参数

限流只是行为中的一项参数、大数据传输会同时在绑定与行为中体现。我们将分别说明


这节开始,说WCF依赖的参数,准确的说,是WCF服务运行所依赖的绑定与行为参数。


我们知道,WCF是面向服务通信框架,它弱化了Server-Client之间的关系,强化了Server-Client通信所依赖的基础:契约。


WCF定义了四种类型的契约

服务(ServiceConract)、数据(DataContract)、错误(FaultContract)、消息(MessageContract)



这节,我们说ServiceConract服务契约,仅仅说参数,即App.config中的参数,因为是这些参数影响了WCF服务接口中方法的行为


对Lig本身,指的是下面接口中的方法的集合


public interface ILigAgent


7.1服务与服务参数


7.1.1  App.config与ServiceModelSectionGroup:
——————————————————————————————————————————————


回头看下LServiceHost中的ApplyConfiguration中的下面这行代码:

/// <summary>
        /// Override ApplyConfiguration to load custom config file
        /// Attention : ConfigPath must be static variable according to the follow rules:
        /// 1. First run ApplyConfiguration of base class of ServiceHost
        /// 2. Second run constructor of LServiceHost itself
        /// </summary>
        protected override void ApplyConfiguration()
        {
            //.....................
            // Gets all service model config sections
            ServiceModelSectionGroup servicemodelSections = ServiceModelSectionGroup.GetSectionGroup(cfg);
            
            //..................
        }



1) App.config由 ServiceModelSectionGroup类维护。

2) 参数最终由ServiceHostChannelFactory<T>使用。这是LServiceHost/LDuplex代码编写所依赖的原理。



ServiceModelSectionGroup

——————————————————————————————————————————————

服务端终结点属性(Services)、客户端终结点属性(Client)、行为属性(Behaviors)、绑定属性(Bindings)。

由ServiceHostBase完成解析App.config并设置这几个属性。 客户端由ChannelFactory<T>解析App.config 

——————————————————————————————————————————————


其实,了解App.config只需要了解ServiceModelSectionGroup信息是如何影响ServiceHost与ChannelFactory的行为就OK了。

这儿,你大概清楚了我们的那个LServiceHost/LDuplex是如何写出来的了。。



图 7.1.1 维护App.config的类


7.1.2 WCF的服务

——————————————————————————————————————————————

WCF的服务是一组公开功能的集合,借宿在特定的进程中。WCF服务分服务接口与服务实现。
在Codes层次,它是一组公开方法的集合。在这儿,如你所见到的在ILigAgent中出现的方法的集合。它通过如下方式被定义为WCF服务接口:

[ServiceContract(CallbackContract = typeof(ILigAgentCallback))]
public interface ILigAgent

如图7.1.2所示


1) App.config中的services节点(服务参数)公开了WCF服务所依赖的配置信息:endpoint


2) Service节点中配置了行为信息(behaviorConfiguration)属性

3) Endpoint中配置了binding属性信息。


了解这2个属性,其本了解了WCF服务端配置的全部。


图 7.1.2 WCF服务端配置


7.1.3 WCF的服务参数解析


——————————————————————————————————————————————

Services中的service节点信息。对Services中的Service节点信息,ServiceHost主要解析了三部分数据:

1) Services属性 

 ServiceModelSectionGroup中的成员

2) behaviorConfuration   

 (BehaviorConguration属性对应的私有成员。此处为什么是小写,实际上ServiceHost使用了BehaviorConguration对应的私有变量behaviorConfuration)
3) binding


Service节点解析:


service节点信息由

public sealed class ServiceEndpointElement

类维护。通过 ServiceHostBase 的如下方法

protected void LoadConfigurationSection(ServiceElement serviceSection)
加载到应用程序。实际上,ServiceEndpointElement信息变成了ServiceElement中Endpoints集合属性中的成员。
这样,我们知道,多个sevice节点信息被加载到了Endpoints集合属性中。


behaviorCOnfuration解析:


BehaviorConguration属性被解析为了IServiceBehavior信息。


Binding解析
而Binding则被解析为了继承于Binding的类,对Lig系统,此处被解析为了 NetTcpBinding类。

public ServiceEndpointElementCollection Endpoints { get; }

图7.1.3 ServiceEndpointElement


到这儿。你基本清楚了WCF配置中的所有参数是如何在ServiceHost中起作用的了。下面我们看具体参数



7.1.4  bindings中的超时配置参数

——————————————————————————————————————————————

整个WCF的绑定模型是一个复杂组件组合体系。本文将抛开信道与信道栈的概念仅从代码层次对bindings参数给予说明。


public abstract class Binding : IDefaultCommunicationTimeouts

Binding 实现了通信超时IDefaultCommunicationTimeouts接口,拥有如下四个参数的行为:



图7.1.4 通信超时接口


private TimeSpan   closeTimeout;
private TimeSpan   openTimeout;
private TimeSpan   receiveTimeout
private TimeSpan   sendTimeout;
public TimeSpan CloseTimeout { get; set; }
public TimeSpan OpenTimeout { get; set; }
public TimeSpan ReceiveTimeout { get; set; }
public TimeSpan SendTimeout { get; set; }


7.1.5 我们关注的是这四个参数是如何影响ServiceHost的

——————————————————————————————————————————————

我们知道,我们的LigServer中有这样的代码:

serviceHost.Open();
//其实它还有一个重载版本,含了超时参数。
public void Open(TimeSpan timeout)

实际上,ServiceHost用的是继承于CommunicationObject中的接口。同时ChannelFactory<T>也继承了该类。所以在服务端与客户端均为有效参数。

public abstract class ServiceHostBase : CommunicationObject

图7.1.5 通信对像接口


ServiceHost & ChannelFactory<T>类间的继承关系


public class LServiceHost : ServiceHost
public class ServiceHost : ServiceHostBase
public abstract class ServiceHostBase : CommunicationObject

public class ChannelFactory<TChannel> :ICommunicationObject


7.1.6 超时参数

 ——————————————————————————————————————————————

1.openTimeout – 服务端、客户端有效配置参数

 

服务开启超时,默认1分钟。

public void Open()


客户端连接超时,默认1分钟。

public TChannel CreateChannel()


2.closeTimeout -服务端、客户端有效配置参数

服务端主动关闭一个连接超时。

客户端关闭一个连接超时

 

3.sendTimeout 服务端、客户端有效配置参数

客户端发送数据超时。默认1分钟。

服务端回调发送数据超时。默认1分钟 (双工通信时配置有效)

 

4.receiveTimeout服务端、服务端配置有效参数

服务端接收数据超时,默认10分钟。

客户端回调接口接收数据超时,默认10分钟(双工通信时配置有效)



7.2  可靠性会话超时参数与Tcp通道消息传输参数


7.2.1 可靠性会话参数

——————————————————————————————————————————————

先看下NetTcpBinding类

图7.2.1 NetTcpBinding类

ReliableSession属性决定了客户端与服务端会话可靠性。(该参数在事务传输中非常有用)


public OptionalReliableSessionReliableSession {get; }
 
public class OptionalReliableSession : ReliableSession
public bool Enabled {get;set; }


Enabled。是否开启可靠会话。对NetTcpBinding绑定,默认不开启。

ReliableSession有一个属性

public TimeSpanInactivityTimeout {get;set; }

 

inactivityTimeout: 表示在客户端和服务器端非活动期间的空闲超时。Enabled属性配置为true时该参数有效。

 

e.g:

如果

<reliableSession enabled = "true" inactivityTimeout = "00:01:00"/>

此时如果WCF客户端1分种不调用WCF服务,则WCF服务端会自动认为客户端已经掉线。此时WCF连接会自动断开。还记不记得我们前面的配置。此处的inactivityTimeout无效。。该种写法是一种画蛇添足。这是我们前面配置中引入的第一个无效参数。

这儿,为什么没写正确的,是因为,错误的东西更容易让人印像深刻。你懂的。


<reliableSession enabled = "false" inactivityTimeout = "00:00:10"/>

可靠性会话关闭,WCF连接由服务端的receiveTimeout配置参数引发。这意味着,如果WCF客户端超过receiveTimeout没有调用服务。WCF连接会自动断开。


inactivityTimeout + receiveTimeout

这2个参数,决定了WCF服务端保持连接状态的最长有效时长。


7.2.2 Tcp通道消息传输限流 –流操作

——————————————————————————————————————————————

WCF通道中的消息传输默认采用缓冲方式,当客户端与服务端交换消息时,这些消息会被放入接收端缓存中,一旦接收到完整信息,就立即被传递。

 然而,对于大数据,这样的缓冲无疑是低效的,因为WCF传递消息要等待缓存消息完整后才被传递。而WCF中提供的流操作正好用于改善该情况。

 

NetTcpBinding中有三个属性。

maxBufferPoolSize="52428800"maxBufferSize="6553600"maxReceivedMessageSize="6553600"

1) 这三个属性于大数据的消息传输,使用这三个参数需要显式的设置transferMode = Streamed启用流操作

2) 同时关闭可靠性传输。所有的消息传递会被转换为二进流。

 

默认情况下transferMode = “Buffered”

 

maxReceivedMessageSize:接收端最大消息长度 单位:字节 。默认64K

maxBufferSize:接收端最大缓冲长度  单位:字节

maxBufferPoolSize:接收消息缓冲区管理器分配的最大内存量 单位:字节

 

启用该属性基本还要设置一个消息复杂度的属性ReaderQuotas,该属性为终结点处理SOAP消息的复杂性约束配置。。。。。

 

maxConnections="100"

maxConnections一个Service节点允许最大连接数量。作用与ServiceThrottlingBehavior 中的限流MaxConcurrentSessions效果等同。

 

7.3 服务限流参数

 

限流参数主要有两项。我说ServiceThrottlingBehavior与DataContractSerializer

 

7.3.1 ServiceThrottlingBehavior 服务调用限流

——————————————————————————————————————————————

WCF对限流的控制是通过一个服务行为(Service Behavior)实现的,该服务行为类型名称为ServiceThrottlingBehavior。含三个参数

 

MaxConcurrentCalls:服务端允许的所有客户端最大并发调用总数,默认16

MaxConcurrentInstances:服务端并发最大实例数。默认26;

MaxConcurrentSessions:服务端允许客户端最大连接数,默认10。



图7.3.1 服务行为限流


7.3.2 DataContractSerializer服务传参限流

——————————————————————————————————————————————

WCF数据契约定义了专门的数据契约序列化器,该序列化器参通过DataContractSerializer表示,用来序列化数据契约中我们的标记为[DataMember]的成员

 

DataContractSerializer 有一个MaxItemsInObjectGraph属性用于设置序列化与反序列化时允许的最大对像数。

 

如果你的服务接口中有如下类型:

[OperationContract]
List<ActiveProfile> GetActiveLogsInfo();

List<ActiveProfile>是一个链表,如果其长度超过65536,在客户调用这样的方法会出现一个通道状态为Fault的错误。。

<behavior name="serializerBehavior">
          <dataContractSerializer maxItemsInObjectGraph="200000"/>
        </behavior>



此,配置我们讲完了。虽然我们没讲客户端配置。但有一点要注意。客户端与服务端完全可以共享一个配置。所以netTcpBinding中出现的参数在客户端要完全一致。

 

若不一致。。

你程序在这儿,就埋下了Bug。等出现的时候,掘地三尺的查吧。自求多福。

 

——————————————————————————————————————————————

再回答最后一个问题:

 ——————————————————————————————————————————————

为什么我们不把服务端配置与客户端配置搞一起,非得整两个配置,多麻烦?

 

1) 你知道,SOA本身就解释为面向服务的架构,就是要减小Server-Client间的耦合。

2) 我们的Server可能在部署在千里之外,客户端与Server共享一个配置,对Server来说,给客户端的配置暴露了Server不该暴露的资源,Server的信息是非安全的。

3) 同时这么做人为的增加了Server-Client间的耦合。这也不是面向对象中封装所要求的做法。。。

 


OK,Lig系统到这儿,算是这章讲得最细节了,是因为参数。详细的原因很简单:

 

1) 我想传递一个信息,作为Coder,我们要非常、非清清楚的知道,我们程序运行所依赖的每一个参数。

2) 我提ORM、提SOA、提设计模式。是因为。你软件的架构在很大程度上决定了你的代码有没有BUG。

 

其实,对每一个优秀的程序员来说,写出没有Bug的程序,应该是最基本的要求。

 因为,你的工作,你代码的稳定程度,决定了你团队代码的质量。

以前我也一直不相信,即便几十万行代码,为什么有人会声称他们的代码是0BUG,直到我自己写出OBUG的代码。。

 

其实,还有个原因,就是因为,《0 bug:C/C++商用工程之道》只回答了一部分答案,还有一部分,需要你自己去寻找。

 

自信,其实、你我、都不希望、真的就是源于无知。你懂的。。。。。好了。



附:客户端与服务端完全可以共享一个配置

(不要使用这个配置.使用时Server/Client配置分开)

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="Lig" value="viviute"/>
    <add key="Ligger" value="define your own config"/>
  </appSettings>
  <system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="ligTcpBinding" closeTimeout="00:02:00" openTimeout="00:02:00" sendTimeout="00:10:00" receiveTimeout="24.00:00:00"
                maxConnections="100" maxBufferPoolSize="409600000" maxBufferSize="102400000" maxReceivedMessageSize="102400000">
          <reliableSession enabled = "false"  inactivityTimeout="10:00:00" />
          <security mode="None" />
        </binding>
      </netTcpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="metaDataBehavior" name="Lig.vivitue.Contract.Services.LigAgent">
        <endpoint address="net.tcp://127.0.0.1:6023/Lig.vivitue.Contract.Services.LigAgent"
                  binding="netTcpBinding" bindingConfiguration="ligTcpBinding"
                  contract="Lig.vivitue.Contract.Services.ILigAgent"/>
      </service>
    </services>
    <client>
      <endpoint name="Lig.vivitue.Contract.Services.LigAgent" behaviorConfiguration="IgoreSvcCertValidation"
                address="net.tcp://127.0.0.1:6023/Lig.vivitue.Contract.Services.LigAgent"
                contract="Lig.vivitue.Contract.Services.ILigAgent"
                binding="netTcpBinding" bindingConfiguration="ligTcpBinding">
        <identity>
          <dns value="vivitue" />
        </identity>
      </endpoint>
    </client>
    <behaviors>
      <serviceBehaviors>
        <behavior name="metaDataBehavior">
          <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:7023/Lig.vivitue.LigMetadata"/>
        </behavior>
        <behavior name="serializerBehavior">
          <dataContractSerializer maxItemsInObjectGraph="200000"/>
        </behavior>
        <behavior name="throttlingBehavior">
          <serviceThrottling maxConcurrentCalls="50" maxConcurrentInstances="200" maxConcurrentSessions="100" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="IgoreSvcCertValidation">
          <clientCredentials>
            <serviceCertificate>
              <authentication certificateValidationMode="None"/>
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值