使命必達: 深入剖析WCF的可靠會話[原理揭秘篇](下)
上麵一部分我們站在信道層的角度剖析了WCF為了實現可靠會話在信道層進行的一係列消息交換,或者說客戶端和服務端的RS信道為了實現可靠消息傳輸所進行一輪又一輪的握手。這一切都是基於這樣一個假設:兩個RS信道均可以在適當的時機向對方發送消息,或者說兩個RS信道之間是一個雙工的通道。
如果我們站在傳輸層看待這個問題,該假設對於TCP傳輸是成立的,但是對於HTTP來說就有點問題了。HTTP本身就是一個基於請求|回複消息交換模式的應用層網絡協議,並不能對雙工通信提供支持。而WCF通過WSDualHttpBinding實現的雙工通信機製和NetTcpBinding支持的雙工通信具有本質的區別。NetTcpBinding創建的傳輸通道就是一個雙工的TCP連接,而WSDualHttpBinding創建的所謂的雙工通道實際上是兩個方向相反的HTTP連接。接下來我們主要討論當我們采用基於HTTP綁定——WSHttpBinding(或者是WS2007HttpBinding)和WSDualHttpBinding)時,實現可靠會話所進行的通信方式。
一、WSHttpBinding V.S. WSDualHttpBinding
如果采用WSHttpBinding,最終創建的是一條從客戶端到服務端的HTTP通道。在這種情況下,客戶端RS信道和服務RS信道之間的多輪握手(CreateSequence/ CreateSequenceResponse、Sequence/ SequenceAcknowledgement、CloseSequence/CloseSequence和TerminateSequence/TerminateSequenceResponse)均是采用這樣的消息交換方式:客戶端將相應的消息通過HTTP請求的形式發送到服務端,相應的回複或者確認通過HTTP回複返回。圖1揭示了上述的幾次握手在傳輸層上的實現,其中實線部分代表HTTP請求,虛線部分代表HTTP回複。
圖1 可靠會話基於通過WSHttpBinding創建的單通道的消息交換
從圖1中我們可以和清晰地看到,CreateSequence/ CreateSequenceResponse、CloseSequence/CloseSequence和TerminateSequence/TerminateSequenceResponse完全是按照HTTP請求/HTTP回複的形式實現的。在進行服務調用的時候,即使采用的單向消息交換模式,發送應用消息的請求依然會接收到一個包含SOAP消息的HTTP回複。服務端通過將確認消息方法每一個HTTP回複之中。
之所以采用如上的方式的根本目的在於,WSHttpBinding創建的傳輸層通道是從客戶端到服務端的一條HTTP連接。HTTP連接是一條單工通道,客戶端和服務端總是扮演者請求者和回複者的角色,服務端不能主動聯係客戶端,此外無論是對RM序列創建、關閉和中指的回複,還是消息確認隻能放在HTTP回複中。
但是,如果我們采用WSDualHttpBinding作為終結點綁定,情況就大不一樣了。由於WSDualHttpBinding會創建兩條HTTP連接構成一個所謂的雙工通道,服務端可以隨時聯係到客戶端,不需要將相應的回饋通過HTTP回複隨帶捎回去。借助於WSDualHttpBinding創建的雙工通道,可靠會話的上述握手采用如下的消息交換方式:客戶端通過HTTP請求將RM序列創建、終止請求以及攜帶Sequence報頭的應用消息發送給服務端,並得到一個狀態為202的空HTTP回複。而真正的回複和消息確認都通過另一個HTTP連接的HTTP請求返回給客戶端的,而這些HTTP請求通過會得到一個狀態為202的空HTTP回複。
圖2是對可靠會話消息交換在傳輸層的反映。可能你會覺得這和我們上麵介紹的WS-RM消息交換模式不一致,沒有了CloseSequence/CloseSequence握手,對於TerminateSequence請求也沒有相應的TerminateSequenceResponse回複,這是因為WSDualHttpBinding支持的WS-RM版本是1.0,而不是我們上麵介紹的1.1。除了上述的兩點不同之前,還有一個不一樣的地方:客戶端在發送RM序列終止請求之前會發送一個攜帶Sequence報頭的空消息,而對於包含在該空消息中的Sequence報頭,除了包含消息序號之外,還具有一個額外的LastMessage元素表明這是RM序列終止前的最後一個消息。關於WS-RM 1.0,限於篇幅的因素,在本書中不可能再進行深入的介紹,有興趣的讀者可以參閱OASIS官方文檔。
圖2 可靠會話基於通過WSDualHttpBinding創建的雙通道的消息交換
我們也可以從另外一種視角來看WSHttpBinding和WSDualHttpBinding對可靠會話的不同實現方式。對於WSHttpBinding創建的單向信道來說,客戶端對於服務端是一個不可尋址(Non-Addressable)的終結點。也就是說,客戶端不能主動向客戶端發起請求,隻能在客戶端對自己發起請求時,被動地將相應的信息通過HTTP回複的形式返回到客戶端。但是,對於WSDualHttpBinding創建的雙工信道,情況就不一樣了。雙工通道是客戶端和服務端成為了對等終結點,無論是服務端還是客戶端,對於對方來說都是可尋址的(Addressable)。服務端可以在任何時候向客戶端發起請求,將相應的信息通過HTTP請求的方式發送給客戶端。
雙工通道成就了可靠會話的“批量確認”機製。為了盡可能地降低網絡流量,接收端RS信道接收到消息之後,並不會立即為該消息進行單獨確認,而是會等待一定的時間(通過ReliableSessionBindingElement的AcknowledgementInterval屬性設置),對之前接收到的消息進行批量確認。由於接收端RS信道接收到消息和發送確認有一定的延遲,我們也稱這種機製為“延遲確認”。
二、單向模式(One-Way)V.S.請求|回複(Request|Reply)和雙工(Duplex)模式
決定實現WCF可靠會話真正采用的消息交換還具有另外一個因素:消息交換模式。單向模式和請求|回複以及雙工模式下,可靠會話采用的消息交換方式具有很大的不同。如果終結點服務契約中的所有操作均是單向的(通過OperationContractAttribute特性的IsOneway屬性設置),對於可靠會話來說僅僅存在一個從客戶端到服務端的RM序列。反映在序列的創建上就意味著在客戶端RS生成的CreateSequence消息中並不存在Offer結點。
從應用層次講,單向操作意味著客戶端向服務端發送消息而不會接收到任何回複。由於服務端不會有任何的應用消息從服務端返回到客戶端,服務端的RS信道隻能創建一個空的SequenceAcknowledgement消息對接收的消息進行確認。
如果終結點服務契約中的所有操作中具有一個以上的非單向操作,WCF可靠會話不僅僅需要保障消息從客戶端到服務端的可靠性,也需要對服務端到客戶端的消息傳輸提供保障,所以WCF可靠會話需要建立兩個方向相反的RM序列。具體來說,可靠會話采用“序列提供”機製創建了雙向的RM序列。在客戶端RS信道生成CreateSequence之前現在本地創建一個RM序列,然後將該序列封裝到CreateSequence消息的Offer元素中“提供”給服務端。服務端RS信道接收到CreateSequence消息之後,處理創建客戶端請求的RM序列之外,還會接受(或者拒絕)提供的序列。
不同於單向模式下采用單獨的SequenceAcknowledgement消息進行消息確認,在請求|回複模式下,為了盡量降低網絡流量,可靠消息采用“背負(piggy-back)”機製實現消息確認。具體來說,客戶端RS信道將SequenceAcknowledgement報頭放到請求消息中,實現對接收到的回複消息的確認;服務端RS信道則將SequenceAcknowledgement報頭放到回複消息中,實現對已經接收到的請求消息的確認。
而雙工(Duplex)是由兩個簡單消息交換模式(單向或者請求|回複模式)組合而成,具體消息交換方式你應該可以上麵接受推導出來,在這裏就不再贅言講述了。
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-27 14:34:37