詳談H.323協議的協議棧開發
前面我們分析了一些協議,以及協議棧的內容。相信大家也都了解了H.323協議的內容了。那么這里我我們就針對這個協議棧開發內容進行一下講解。開發H.323協議棧是通信設計過程中的一項極其艱巨的任務,難點主要在于:復雜的協議棧開發需要投入數年的工程設計資源,而且掌握這些復雜的標準還需要一個知識的積累和學習過程,本文將探討開發H.323協議棧和VoIP應用系統遇到的問題、歧義、困難等。
利用基于原語(primitive)的H.323協議棧開發IP承載話音(VoIP)應用系統不是一項小任務,因為創建一個魯棒的應用系統,需要花很多時間去研究含糊的標準和復雜的狀態機。
本文用例子說明流程的實現以及原語(primitive)的定義,用以說明如何構建一個基于原語接口的應用系統和一個基于簡單接口的替代方案。在開發協議棧之前,建議瀏覽一下H.323的基本標準。H.323是國際電信聯盟(ITU)頒布的標準,由一系列特定協議組成,包括Q.931、H.225、H.245和ASN.1。為了提供呼叫信令功能,H.323部分融合了H.225和Q.931標準。H.245定義了多個流程,以便于進行能力信息互換(exchange capability)、主從判斷(master-slave determination)和信道(channel)信令。最后,ASN.1規定了數據格式,使兼容H.323的端點能夠互通。
基本概念
使用H.323時,正確理解原語和流程這兩個術語很關鍵。原語用來描述應用層和H.323協議棧下層之間傳遞的結構或消息。H.323定義了多個原語,有四種類型:請求、指示、響應和確認。每個原語的參數的數量是可變的,這由相關流程決定。這些參數表示應用層和協議棧下層的通信信息。
在H.323協議族中的每個協議定義了一組流程。每個流程代表一個狀態機,在大多數情況下,該狀態機用原語的形式規定一組消息,這些消息以特定的順序發送和接收。這些原語便于應用層和下層的通信。
流程提供具體的功能,可以異步啟動或終止,或啟動后在整個對話過程中保持激活狀態。例如,H.245流程包括主從判斷、能力信息互換、單向和雙向信道信令。其中,只有信令信道在實際的對話過程中保持激活。其它只是激活后發送和接收數據,然后就終止了。Q.931/H.225流程包括呼叫建立和拆除。圖1表示一個完整的H.323協議棧開發的實現。值得指出的是,該實現依賴于網絡協議棧和實時操作系統(RTOS)。多數應用系統需要RTOS以便同時處理多個流程和/或呼叫。
#p#
呼叫信令
如上所述,H.323融合了Q.391和H.225協議,可提供呼叫信令功能。實際上,Q.931是ISDN相關的協議,用于建立和拆除呼叫。盡管從來沒有打算應用于VoIP應用系統,但是通過在該協議上增加信息,可以為H.323提供比較類似的相關功能。
Q.931分組(packet)包含多個稱為信息單元(information element)的參數。例如,Q.931分組可以包含一個用戶信息單元。H.323規定用戶信息單元必須包含一條H.225消息。H.323的附加信息存于此。有關網關、網守(gatekeeper)和協商的大部分信息由H.225承載。
Q.931和H.225定義呼叫信令,而H.245定義許多呼叫業務。最常用的業務包括主從判斷、能力信息互換、信道信令。當Q.931建立起呼叫,這些流程啟動。此時,兩個終端已經同意互連,但是還沒有收發多媒體數據。
主從判斷流程協商決定哪個終端是主,哪個是從。該流程可應用于:將一次協商中相同類型的媒體數據流聯系起來;避免和解決由于編解碼器間的依賴關系造成的沖突。
能力(capability)信息互換流程告知遠程終端的音頻、視頻或數據能力。這可以避免能力猜測過程(即建立一個信道并發送遠程終端可能無法識別的數據)。
邏輯信道信令過程協商建立實時協議/實時控制協議(RTP/RTCP)信道,用于收發多媒體數據。
定義數據
抽象語法表示法(ASN.1)標準詳盡說明了怎樣表示語法或結構化數據分組,它用于在本地和遠程端點間發送H.225和H.245消息。X.691規定了在ASN.1語法結構和網絡接收的原始數據之間的編碼和解碼方法。H.225和H.245等ITU標準都為所有的協議消息規定了ASN.1語法結構。
RTP和RTCP也包括在H.323之中。RTP定義了一個消息頭,附加到多媒體數據分組的前端,并通過用戶數據報協議(UDP)發送。消息頭包含了有關多媒體數據的信息,包括順序號和時間戳。RTCP用這些數據來收集網絡性能統計信息,例如分組間的抖動(測量分組到達時間的不規則性)和分組片段的丟失。
協議棧開發
開發H.323協議棧是一項艱巨的任務。困難產生于標準定義不詳盡而且不一致。標準的模糊導致互操作問題,且所實現的協議棧移植性差。
Q.931和H.225定義了呼叫信令流程,但是定義不夠充分。與H.245相比,Q.931和H.225定義的原語缺乏充分的文字說明。另外,產生混亂的原因是不完整的ASN.1標準,因而開發人員需要將X.691編碼格式數據反向轉換。RTP/RTCP、H.245和應用層間的關系也存在問題。
在H.323中,Q.931和H.225協議進行了融合,但是融合不夠好。尤其是Q.931規范包含一些描述很充分的流程圖,這些流程圖顯示相關消息、原語和超時之間的關系。而H.225將Q.931中的多個消息標記成“禁用”,但卻沒有規定反映這些變化的新流程。這樣,H.225缺乏足夠的信息,因此,開發者得到的文檔不完善。
與此相反,H.245是一個定義清晰的協議,具有大量的流程圖。與Q.931和H.225不同,它規定了每個原語的參數。這是極其有用的,而且這表明了Q.931和H.225的缺陷。盡管Q.931是基于原語的,但是沒有規定原語的字段。整個H.225標準只有一次提到原語而且沒有提供包含參數的信息。為每個原語選擇字段的工作留給了開發者,因此,Q.931的接口變成專有的和不可移植的接口。
影響H.323協議棧開發學習曲線的主要方面是ASN.1。盡管ASN.1詳細說明了怎樣描述語法,但是,將語法結構編碼成字節流的方法有多個。X.691規定了打包編碼原則(PER),是H.225和H.245使用的編碼規則集。不幸的是,X.691的不足削弱了ASN.1的優點。ASN.1具有擴展給定語法的能力,而且能夠以完全后向兼容的方式編碼。但是,X.691只粗略地解釋了怎樣進行編碼擴展。為了彌補X.691標準的不足,需要做大量的反向工程工作。通過購買現成的協議棧開發產品可以避免該任務。
RTP/RTCP和其它H.323相關協議的結合引入了更多難于捉摸的標準問題。為了設計一個模塊化的H.323協議棧,需要在標準規定的范圍內仔細定義各協議間通信的信息結構。H.323標準不能清晰地描述各協議的互通性。RTP/RTCP就是這種缺陷的一個范例。#p#
實時協議問題
RTP/RTCP是設計者的大難題,因為很難從標準中推斷出它與其它協議的關系。可能有兩種選擇:在應用層進行RTP/RTCP處理或者在下層協議中處理。
如果在應用層處理RTP/RTCP,應用程序必須知道RTP信道使用的端口號。因為使用原語進行協議棧通信,H.245原語必須能夠將所有需要的端口信息傳送給應用層。但是,這些原語沒有描述遠程主機端口號的參數。因此,需要以非標準方式修改這些原語,增補缺少的信息。
如果在下層處理RTP/RTCP,協議棧開發需要有關編解碼器的信息以便調用合適的設備驅動程序。然而,該解決方案也不夠合理,因為協議棧必須知道特定的設備信息,而這是不可移植的。
創建VoIP應用系統
為了更好地理解如何利用H.323協議棧實現VoIP應用系統,讓我們看幾個例子,它們展示了下層協議和應用層之間的交互關系。
要利用基于原語的H.323協議棧實現的基本的VoIP應用系統,必須實現一組由H.323標準定義的流程。這些流程由可重入狀態機組成,基于輸入或輸出原語的消息由狀態機執行。另一個替代方案是面向任務的,為每一個流程啟動一個新線程。無論哪種方案,用原語表示的輸入或輸出消息都是異步發生的。應用系統程序必須把狀態值保持在這些流程中,而且某些流程可能會有多個運行實例。
每個原語包括多個參數,這些參數必須在應用層定義。在Q.931中,參數相當簡單且易于理解。然而,當學習H.245協議時,閱讀復雜的ASN.1表結構是很困難的。有關能力集(capability set)流程的原語尤其復雜,ASN.1結構可能嵌套5到6層深。對于不熟悉ASN.1的人來說,這可不是簡單工作。
本地流程時序
另一個核心開發問題是時序,即為了建立或拆除對遠程主機的呼叫,本地流程所執行的時序。當考慮其它H.323實現或應用的互操作性時,研究時序問題尤其必要,這類系統的實例有Microsoft的NetMeeting和NetSpeak的WebPhone。盡管H.323規范揭示了流程之間的依賴關系,必須通過實驗測試和反向工程來揭示發起呼叫并建立通信需要的時序。
#p#
圖2展示了與遠程終端建立通信關系時H.323協議棧必須執行的流程。注意,同一水平線上的流程可能同時運行,但是他們都完成后該時序才能繼續下去。
Q.931呼叫建立流程啟動呼叫建立過程并且通知遠程終端有一個呼入。當呼叫建立起來后,某個終端可能啟動H.245規定的主從判斷流程或能力信息互換流程。每個終端都需要執行能力信息互換流程,但是只要一個終端執行主從判斷流程就可以了。主從判斷和能力信息互換完成后,邏輯信道打通了。最后,該對話通過另一個Q.931流程關閉。
盡管該時序看起來直接明了,而且一些依賴關系在標準中定義的比較松散,因而很難實現該時序。因為僅依賴關系就占了H.245規范的257頁還多,實現時很容易疏忽。
另一個導致混亂的問題起因于異步執行的流程。例如,主從判斷流程可以在能力信息互換流程之前或之后執行,而且可能同時或者相互覆蓋執行。更有甚著,能力信息互換流程可能在一個閃斷信道(on the fly once channel)上執行。這樣可以在對話期間動態改變編解碼器,然而給協議棧開發增加了工作負擔。
實現流程
H.323定義Q.931為呼叫信令協議,在此,將描述怎樣實現實際的流程。基于原語的H.323協議棧開發要求應用程序開發者定義原語并用其與下層通信。為了方便描述呼叫建立流程,我們從Q.931規范的25頁文檔中歸納出一個流程圖(如圖3)。
當實現呼叫建立流程時,首先發送建立請求消息,然后該流程等待一條告警指示消息。當該指示消息接收到后,該流程再次等待一條確認消息。如果這條確認消息也接收到了,該流程終止,應用程序可以開始處理H.245流程。
為了開發基于原語的H.323協議棧流程的狀態機,開發者需要精通H.323協議,例如上述Q.931呼叫建立協議。注意,H.245流程比Q.931更具有面向狀態的特點。每個H.245流程必須按照標準規定的時序處理接收到的指示消息并發送請求消息。每個狀態機的具體實現將需要數月時間。
如果采用替代方案,H.323協議棧開發不使用原語,協議棧需要包括一個已經實現了上述流程和狀態機的中間層,并提供一個簡化的應用編程接口(API)。對于前面的例子,協議棧要發一個呼出,只需要調用下面這一個函數即可:
在使用API實現的系統中,makeCall()函數接受遠程端點的主機名字(hostname)和IP地址,并執行所有呼叫遠程終端的步驟。該方案需要一個流程構造前述的原語,實現處理所有輸入輸出原語的狀態機。使用基于API的協議棧不需要理解原語接口,可以節省數月的開發時間。
給原語參數賦值
前文的例子描述了流程的實現。下面的例子展示怎樣給原語賦值,以能力信息互換流程的“TRANSFER.request”原語為例。
“TRANSFER.request”原語有四個字段,用ASN.1格式填充。這四個字段是PROTOID、MUXCAP、CAPTABLE 和 CAPDESCRIPTORS。在此,我們集中討論CAPTABLE參數,它是特定終端支持的所有編解碼器的列表。在此例中,填充的CAPTABLE參數表示以下終端能力:單一G.711 A律64k編解碼器,能夠接收的分組長達180ms音頻數據。下面的偽碼是初始化一個ASN.1結構元素的基本步驟。
CAPTABLE參數實際上是CapabilityTableEntry的數組。填充該參數的第一步是為該數組分配內存空間。每個被支持的編解碼器都需要一個CapabilityTableEntry。在本例中,數組只有一個元素,因為只支持G.711編解碼器。每個CapabilityTableEntry有兩個元素:TableEntryNumber字段和可選的能力信息結構。
CAPTABLE[0].Capability.TableEntryNumber = 1 (1)
在行1的語句中,CapabilityTableEntryNumber任意設置,但是在同一消息中取值要不同。該參數由CAPDESCRIPTORS參數使用,以描述編解碼器之間的依賴關系。CAPDESCRIPTORS結構要復雜得多,不在本文討論范圍內。
能力信息結構描述了至少12種基本能力/業務中的一種。該結構是可選的,但是不選用的情況不多。在特定的應用方式下,ReceiveAudioCapability被選用。像ReceiveAudioCapability的AudioCapability結構包含14多種不同的編解碼器中的一種。用戶必須選用其中一種編解碼器。一旦選用了某特定的編解碼器,相關字段必須定義。在g711Alaw64k情況下,只需要一個字段。第二行語句表示編解碼器驅動器能夠處理的分組大小至多180ms。
CAPTABLE[0].capability.receiveAudioCapability.g711Alaw64k = 180 (2)
值得注意的是,這個簡單例子在一個參數中只定義了一個編解碼器。其它原語和參數如CAPDESCRIPTORS要復雜得多。處理這種原語的過程枯燥、耗時且會給項目造成不必要的困難。
如果采用替代方案,開發者使用簡單的API協議棧,則不需要關心這些細節。只要給出用ASN.1正確描述的編解碼器驅動器,一個在用戶層的簡單的函數調用就能處理所有這些細節:
獨立進行簡單API協議棧研究和開發,只需投入數百個工時去解決有關ASN.1的問題就可以了。在應用層,僅僅RegisterCodec()函數就可以為開發者節省相當多的時間。當成本和上市時間最重要時,該協議棧開發的簡單性具有不可估量的價值。