1、ACK在SIP INVITE中作用
在前面的文章中,我們已經完整介紹了關于100 Trying和可靠性傳輸的關系,并且我們耗費了很多篇幅討論100 Trying的問題和細節(jié)。很多讀者可能也想到了,如果要完成一個完整的可靠性傳輸,200 OK的傳輸也是必不可少的環(huán)節(jié)。如果200 OK傳輸出現問題,當然,后面也不可能出現ACK的傳輸。因此,在討論ACK之前,首先討論一下簡單的200 OK傳輸的流程。

在200 OK傳輸過程啟動時,被呼叫方響應就會啟動另外一個定時器來計時。如果對端在超時后沒有收到200 OK,則說明200 OK丟失,重新發(fā)送,直到呼叫方收到200 OK,然后發(fā)送ACK請求,直到被呼叫方最終收到ACK請求消息,確?煽啃詡鬏數耐耆瓿。接下來,我們討論一下ACK的角色。
2、關于SIP中ACK的疑惑
很多讀者可能對ACK有一些疑惑。ACK好像沒有自己啟動什么流程,不像其他的請求,例如INVITE那樣可以啟動一個請求。那么,ACK到底是一個request請求還是response響應? 根據RFC3261的對request和response的定義,request定義中規(guī)定,請求必須有Method 類型,而response必須以狀態(tài)碼和響應短語構成。在RFC3261 7.1和7.2中有這樣的語法規(guī)范:
- Request:
- Request-Line = Method SP Request-URI SP SIP-Version CRLF
- responses:
- Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF

以下示例簡單說明了什么是請求和響應的區(qū)別。因此,從定義來說,ACK是一個請求 method。

但是,讓讀者感到迷惑的是,如果是一個request的話,request至少需要啟動流程執(zhí)行什么動作,但是好像ACK并自己啟動流程,ACK僅負責發(fā)送了響應消息。實際上,ACK也僅負責對可靠性傳輸的最終確認。因此,無論讀者有什么樣的迷惑,根據RFC3261的規(guī)范,ACK仍然是一個request。
3、ACK本身就是一個transaction
剛才,筆者已經在前面提到,ACK的概念好像和請求的規(guī)定有一些沖突,但是,ACK的語法是符合對request的定義的,因此它仍然是一個請求。筆者希望讀者明確這個概念。但是,如果我們討論到SIP transaction時,很多用戶就非常迷惑ACK的使用。為什么在INVITE的示例中,ACK是獨立的一個transaction呢?為了回答這個問題,我們需要根據RFC3261的規(guī)范來說明ACK。
根據SIP transaction-17的定義,一個transaction必須是以request開始,以一個或者多個最終response結束,中間可以支持多個臨時響應。
- Specifically, a SIP transaction consists of a single request and any responses to
- that request, which include zero or more provisional responses and
- one or more final responses.

但是,在RFC3261-17中,transaction另外有一段對transaction的特別說明,可能一般讀者沒有注意到這段說明解釋。它是這樣定義的:
In the case of a transaction where the request was an INVITE (known as an INVITE transaction)
,If the response was a 2xx, the ACK is not considered part of the transaction.

按照這個定義,ACK就可以構成自己獨立的transaction,因此,如果滿足了以上條件的話(這里的響應是200 OK),那么,ACK本身自己就是一個transaction。
如果讀者能夠理解以上解釋,讀者可能就徹底理解了為什么在一個完整的呼叫流程中,ACK是一個獨立的transaction。
4、僅INVITE中才能看到ACK
在SIP呼叫中,我們?yōu)槭裁粗荒茉贗NVITE的請求中看到ACK,其他的請求中卻沒有看到ACK(例如BYE中)?

BYE中則沒有看到ACK的出現:
下面,我們解釋一下其中的原因。 其實原因也很簡單。大部分情況下,INVITE的請求發(fā)送以后,電話系統(tǒng)需要人工干預,例如需要等被呼叫方來接聽,而其他的請求則無需人工干預,例如BYE和注冊。下面,我們解釋一下非INVITE請求中為什么沒有出現ACK。
BYE請求是一種無ACK的使用場景。如果一方掛機的話,無需另外一方進行人工干預。,例如,被呼叫方僅通過終端自動簡單回復200 OK就可以實現整個流程的完整性。
同樣,注冊也是一樣的道理,如果UAC需要對服務器端發(fā)送注冊請求時,服務器端僅根據注冊請求的信息來驗證其身份即可,無需進行人工干預。服務器端驗證UAC的信息,則會自動返回一個最終響應消息。
但是,如果是INVITE請求的話,則實現的流程完全不同。因為,如果呼叫方發(fā)起呼叫以后,對端話機振鈴。在振鈴時間內,如果被呼叫方不在工作臺的話,電話一直振鈴,系統(tǒng)需要花費一定時間來等待被呼叫方應答,接聽電話,這時是需要人工干預來完成一個可靠性傳輸過程。當然,用戶可以通過一些軟交換呼叫路由的設置(SIP頭添加alter-info:ring answer),終端電話(設置 Ring Answer)也可以實現呼叫的自動應答,這是另外一個話題。

通過以上例子,我們可以看到,其他的非INVITE都可以通過自動化的處理方式來實現,無需人工干預。因此,只有INVITE中帶有ACK請求回復,而沒有看到其他的請求中帶ACK的請求回復。
5、ACK的其他討論
因為篇幅的關系,筆者還沒有完全討論ACK的語法和完整的細節(jié),因為ACK請求涉及了很多不同的場景,并且靈活性也很大,具體的細節(jié)建議大家查閱RFC3261。這里,我們簡單討論結果可能經常遇到的問題。
首先,在涉及到SIP transaction中,大家需要注意,在INVITE的ACK是一個獨立的transaction(剛才我們已經提及)。
其次,ACK在某些場景中可能被忽略,例如在無狀態(tài)的服務器端對ACK的處理機制。根據RFC3261 8.2.7的規(guī)范,無狀態(tài)UAS中必須忽略ACK請求。這個一定要注意。
最后,ACK的處理機制依賴于最終響應的類型。在UAC發(fā)起發(fā)起初始化請求,UAC需要對每個最終響應(300-699)發(fā)送一個響應消息,但是處理這個ACK的機制完全取決于response的響應類型。在transaction進行處理時遵從具體的規(guī)則。關于規(guī)則的定義,讀者可以查閱REFC3261的17章節(jié)。
6、總結
在本文章中,筆者首先介紹了ACK在INVITE呼叫流程中的構成和其必要性,然后筆者解釋了ACK到底是請求還是一個響應的疑惑,接下來筆者討論了非INVITE請求中沒有帶ACK的原因,最后,筆者討論了ACK幾個其他方面需要特別注意的地方。
通過以上討論,筆者為讀者提供了相對比較全面的ACK的了解。為了解釋的便利,筆者在示例中僅使用了點對點的呼叫并沒有涉及多個代理之間的呼叫和多個hop的處理。因此,對ACK的流程處理的討論相對比較基礎和簡單。如果討論討論比較復雜的ACK處理機制,需要涉及其他的SIP的概念和內容,因為篇幅的關系不再做過多展開討論,希望讀者諒解,我們在未來的章節(jié)中會根據實際內容的安排做更加深入地討論。
參考資料:
https://tools.ietf.org/html/rfc3261
https://arxiv.org/pdf/0807.1160.pdf
https://tools.ietf.org/html/rfc5407


關注微信公眾號:asterisk-cn,獲得有價值的Asterisk行業(yè)分享
Asterisk freepbx 中文官方論壇:http://bbs.freepbx.cn/forum.php
Asterisk freepbx技術文檔: www.freepbx.org.cn
融合通信商業(yè)解決方案,協同解決方案首選產品:www.hiastar.com