WCF後傳系列(5):深刻WCF尋址Part 5—邏輯地址和物理地址

概述

在WCF中,每一個服務終結點都與兩個地址相關聯,一個邏輯地址和一個物理地址,邏輯地址就是SOAP消息的目標地址,即前面不止一次提到的「To」地址,而物理地址是WCF偵聽器真正監聽的地址。在WCF中,邏輯地址稱之爲終結點地址Endpoint Address,而物理地址則稱之爲監聽地址ListenUri。
本文將詳細介紹WCF中的物理地址和邏輯地址,以及如何使用tcpTrace來進行SOAP消息的跟蹤。

兩種地址

WCF中,物理地址負責使用特定的傳輸協議在特定的位置接收傳入的消息,除非特別指定,不然邏輯地址將被用來作物理地址,換句話說,在之前咱們對於終結點所配置的EndpointAddress都是指定了邏輯地址,如咱們的服務端配置以下:
<endpoint address="[url]http://localhost:8887/CalculatorService1[/url]"
          binding ="wsHttpBinding"
          contract="TerryLee.WCFAddressing.Contract.ICalculator">
</endpoint>
<endpoint address="[url]http://localhost:8887/CalculatorService2[/url]"
          binding ="basicHttpBinding"
          contract="TerryLee.WCFAddressing.Contract.ICalculator">
</endpoint>
如今咱們輸出一下,就能夠看到兩個地址是一樣的值,以下代碼所示:
using (ServiceHost calculatorServiceHost =
        new ServiceHost(typeof(CalculatorService)))
{
    calculatorServiceHost.Opened += delegate
    {
        Console.WriteLine("Service begin to listen via the Address:{0}",
            calculatorServiceHost.BaseAddresses[0].ToString());
    };
    calculatorServiceHost.Open();
    foreach (ServiceEndpoint se in calculatorServiceHost.Description.Endpoints)
    {
        Console.WriteLine("Endpoint details:");
        Console.WriteLine("Logical address: \t{0}", se.Address);
        Console.WriteLine("Physical address: \t{0}", se.ListenUri);
        Console.WriteLine("Binding: \t{0}", se.Binding.Name);
        Console.WriteLine();
    }
    Console.Read();
}
輸出結果如圖1所示:
TerryLee_WCF_13
圖1

設定物理地址

前面咱們輸出的結果邏輯地址和物理地址是相同的,咱們能夠經過代碼或者配置文件來設定終結點的物理地址。
WSHttpBinding wsbinding = new WSHttpBinding();
calculatorServiceHost.AddServiceEndpoint(
    typeof(ICalculator),
    wsbinding,
    "urn:calcservice",  // 邏輯地址
    new Uri("http://localhost:8887/CalculatorService")  // 物理地址
);
又或者經過配置文件來設置ListenUri,以下代碼所示:
<endpoint address="urn:calcservice"
          binding ="wsHttpBinding"
          contract="TerryLee.WCFAddressing.Contract.ICalculator"
          listenUri="[url]http://localhost:8887/CalculatorService[/url]"
          bindingConfiguration="securityBinding">
</endpoint>
這裏咱們只須要注意的是在指定物理地址時,仍然可使用相對地址,這一點與設置邏輯地址時是同樣的。

工做原理

如今思考一個核心的問題,當咱們定義了終結點後,在WSDL中包含的是每一個終結點的邏輯地址,而非物理地址,以下代碼片斷:
<wsdl:service name="CalculatorService">
  <wsdl:port name="WSHttpBinding_ICalculator" binding="tns:WSHttpBinding_ICalculator">
    <soap12:address location="urn:calcservice" />
    <wsa10:EndpointReference>
      <wsa10:Address>urn:calcservice</wsa10:Address>
    </wsa10:EndpointReference>
  </wsdl:port>
</wsdl:service>
若是物理地址與邏輯地址相同的,就不會有任何問題,可是客戶端如何與一個配置了不一樣物理地址的服務進行交互?由於客戶端並不關心服務端是否配置了不一樣的物理地址,它只知道每一個終結點有一個惟一的終結點地址,只須要跟該地址交互便可,該地址也將做爲SOAP消息放在「To」標頭中。
這時咱們須要有一個特殊機制,來通知客戶端要使用的物理地址,而後客戶端經過物理地址傳送外發消息,就如同它是路由器或者某種類型的中介同樣,能夠經過ClientViaBehavior來實現這一點,以下代碼所示:
<system.serviceModel>
  <client>
    <endpoint address="urn:calcservice"
              binding="wsHttpBinding"
              contract="TerryLee.WCFAddressing.Contract.ICalculator"
              name="defualtEndpoint"
              behaviorConfiguration="calculatorEndpointBehavior"
              bindingConfiguration="securityBinding">
    </endpoint>
  </client>
  <behaviors>
    <endpointBehaviors>
      <behavior name="calculatorEndpointBehavior">
        <clientVia viaUri="[url]http://localhost:8887/CalculatorService[/url]" />
      </behavior>
    </endpointBehaviors>
  </behaviors>
</system.serviceModel>
此時客戶端將經過與服務終結點相同的物理地址( [url]http://localhost:8887/CalculatorService[/url])向外傳送消息而不是經過「urn:calcservice」,但請注意,在SOAP消息「To」標頭中包含的仍然是邏輯地址,如圖2所示:
TerryLee_WCF_14
圖2
看到上面這幅圖,可能你們還有一個疑問,邏輯地址起什麼做用呢?別忘了咱們前面講到的消息篩選,當消息到達時,ChannelDispatcher 查詢每一個相關的 EndpointDispatcher 對象以肯定終結點是否能夠接受消息,以及將該消息傳遞到能夠接受消息的終結點。當消息的目標地址(To標頭中的地址)與 AddressFilter 屬性相匹配而且消息操做與 ContractFilter 屬性相匹配時,EndpointDispatcher 對象負責處理來自 ChannelDispatcher 的消息。

物理地址模式

瞭解了物理地址和邏輯地址之間的關係,咱們再看一下在設置監聽地址時的兩種模式,經過ListenUriMode枚舉來指定,它定義了兩個枚舉值:
Explicit:徹底原樣使用 ListenUri,默認值。
Unique:指定傳輸是否應使用特定傳輸機制,以確保 ListenUri 是惟一的
根據傳輸所採用的協議不一樣,WCF會採用不一樣的策略來保證ListenUri惟一,具體的策略以下所示:
1.非TCP傳輸,在ListenUri的末尾附加一個GUID。
2.對於獨佔模式下的 TCP(PortSharingEnabled 爲 false),綁定到一個惟一可用端口號。
3.對於端口共享模式下的 TCP(PortSharingEnabled 爲 true),在ListenUri的末尾附加一個GUID。

TcpTrace消息截獲

前面講了這麼多物理地址和邏輯地址,它們最重要的使用地方就是作路由。咱們經常使用tcpTrace來作SOAP消息跟蹤,它正是利用這一點技術,在客戶端配置ClientViaBehavior,指向tcpTrace的偵聽地址,而後tcpTrace在對消息作記錄後再轉發到服務端,如在服務端的配置以下,它的物理地址和邏輯是相同的:
<service name="TerryLee.WCFAddressing.Service.CalculatorService"
         behaviorConfiguration="calculatorBehavior">
  <host>
    <baseAddresses>
      <add baseAddress="[url]http://localhost:8887/Calculator[/url]"/>
    </baseAddresses>
  </host>
  <endpoint address="[url]http://localhost:8887/CalculatorService[/url]"
            binding ="wsHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator">
  </endpoint>
</service>
客戶端的配置,這裏「[url]http://localhost:8887/CalculatorService[/url]」是真正的服務地址(邏輯地址),咱們經過ClientViaBehavior告訴客戶端物理地址是「[url]http://localhost:8080/CalculatorService[/url]」,事實上處於該物理地址的服務並不存在,該地址是tcpTrace的監聽地址:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint address="[url]http://localhost:8887/CalculatorService[/url]"
                binding="wsHttpBinding"
                contract="TerryLee.WCFAddressing.Contract.ICalculator"
                behaviorConfiguration="calculatorEndpointBehavior">
      </endpoint>
    </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="calculatorEndpointBehavior">
          <clientVia viaUri="[url]http://localhost:8080/CalculatorService[/url]" />
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>
tcpTrace的配置如圖3所示:
TerryLee_WCF_16
圖3
這裏tcpTrace監聽的端口號就是咱們在客戶端配置的物理地址端口號,而分發地址纔是服務的真正地址,最終能夠看到截獲的消息,如圖4所示:
TerryLee_WCF_17
圖4
若是不在客戶端配置ClientViaBehavior,利用物理地址和邏輯地址的知識,咱們還能夠有另一種方式使用tcpTrace。前面我說過,邏輯地址是包含在WSDL中,因此對於客戶端來講知道的是邏輯地址,它會向該地址發送消息,這樣咱們能夠配置終結點的邏輯地址爲tcpTrace偵聽的地址,而爲服務端指定另一個物理地址,並配置tcpTrace向該物理地址轉發消息,如服務端的配置以下:
<service name="TerryLee.WCFAddressing.Service.CalculatorService"
         behaviorConfiguration="calculatorBehavior">
  <host>
    <baseAddresses>
      <add baseAddress="[url]http://localhost:8080/Calculator[/url]"/>
    </baseAddresses>
  </host>
  <endpoint address="[url]http://localhost:8887/CalculatorService[/url]"
            binding ="wsHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator"
            listenUri="[url]http://localhost:8080/CalculatorService[/url]">
  </endpoint>
</service>
而客戶端則不用再配置ClientViaBehavior,以下代碼所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint address="[url]http://localhost:8887/CalculatorService[/url]"
                binding="wsHttpBinding"
                contract="TerryLee.WCFAddressing.Contract.ICalculator">
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>
如今「[url]http://localhost:8887/CalculatorService[/url]」是邏輯地址,配置tcpTrace監聽該地址,並向服務的物理地址「[url]http://localhost:8080/CalculatorService[/url]」轉發消息,如圖5所示:
TerryLee_WCF_18
圖5
能夠看到,利用物理地址和邏輯地址的知識,能夠輕鬆的實現路由,固然tcpTrace只是路由中很是簡單的一種使用,後面咱們還會講到更加複雜的應用。

結束語

本文詳細介紹了WCF中的物理地址和邏輯地址,它的相關原理以及如何使用tcpTrace來實現SOAP消息的跟蹤。關於WCF尋址相關文章:

Ctrl+Enter 發佈html

發佈java

取消jquery

推薦專欄更多

帶你玩轉高可用

前百度高級工程師的架構高可用實戰

共15章 | 曹林華

¥51.00 510人訂閱
負載均衡高手煉成記

高併發架構之路

共15章 | sery

¥51.00 579人訂閱
基於Python的DevOps實戰

自動化運維開發新概念

共20章 | 撫琴煮酒

¥51.00 545人訂閱
網工2.0晉級攻略 ——零基礎入門Python/Ansible

網絡工程師2.0進階指南

共30章 | 薑汁啤酒

¥51.00 1956人訂閱
全局視角看大型園區網

路由交換+安全+無線+優化+運維

共40章 | 51CTOsummer

¥51.00 2397人訂閱

掃一掃,領取大禮包linux

0git

分享
lihuijun
相關文章
相關標籤/搜索