在SIP消息中,我们经常会看到ACK的消息。一般情况下,在INVITE的完整流程的最后,我们可以看到ACK。但是,有时,我们又没有看到ACK,ACK可能在传输过程中丢失。如果我们没有最终的ACK消息,怎么能够保证一个完整的可靠性传输呢? 另外,我们在其他的SIP 请求中好像没有看到ACK,仅支持了INVITE。在本文章讨论中,笔者专门使用点对点呼叫中的ACK做一个讨论和解惑,和大家共同学习。
01
ACK在SIP INVITE中作用
在前面的文章中,我们已经完整介绍了关于100 Trying和可靠性传输的关系,并且我们耗费了很多篇幅讨论100 Trying的问题和细节。很多读者可能也想到了,如果要完成一个完整的可靠性传输,200 OK的传输也是需要保证。如果200 OK传输出现问题,当然,后面也不可能出现ACK的传输。因此,在讨论ACK之前,首先讨论一下简单的200 OK传输的流程。
在200 OK传输过程启动时,被呼叫方响应就会启动另外一个定时器来计时。如果对端在超时后没有收到200 OK,则说明200 OK丢失,重新发送,直到呼叫方收到200 OK,然后发送ACK请求,直到被呼叫方最终收到ACK请求消息,确保可靠性传输的完全完成。接下来,我们讨论一下ACK的角色。
02
关于SIP中ACK的疑惑
很多读者可能对ACK有一些疑惑。ACK好像没有自己启动什么流程,不像其他的请求,例如INVITE那样可以启动一个请求。那么,ACK到底是一个request请求还是response响应? 根据RFC3261的对request和response的定义,request定义中规定,请求必须有Method 类型,而response必须以状态码和响应短语构成。在RFC3261 7.1和7.2中有这样的语法规范:
Request:
Request-Line = Method SP Request-URI SP SIP-Version CRLF
responses:
Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
以下示例简单说明了什么是请求和响应的区别。因此,从定义来说,ACK是一个请求 method。
但是,让读者迷惑的是,如果是一个request的话,request至少需要需要启动流程执行什么动作,但是好像ACK并没有执行什么流程,ACK好像仅负责发送了响应消息。实际上,ACK也仅负责对可靠性传输的最终确认。因此,无论读者有什么样的迷惑,ACK仍然是一个request。
3
ACK本身就是一个transaction
刚才,笔者已经在前面提到,ACK的概念好像和请求的规定有一些冲突,但是,ACK的语法是符合对request的定义的,因此它是一个请求。笔者希望读者明确这个概念。但是,如果我们讨论到SIP transaction时,很多用户就非常迷惑ACK的使用。为什么在INVITE的示例中,ACK是独立的一个transaction呢?为了回答这个问题,我们需要根据RFC3261的规范来说明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。
04
只有INVITE中才能看到ACK
在SIP呼叫中,我们为什么只能在INVITE的请求中看到ACK,其他的请求中却没有看到ACK(例如BYE中)?
BYE中则没有看到ACK的出现:
下面,我们解释一下其中的原因。 其实原因也很简单。大部分情况下,INVITE请求发送以后,电话系统需要人工干预,例如需要等被呼叫方来接听,而其他的请求则无需人工干预,例如BYE和注册。
BYE请求是一种无ACK的使用场景。如果一方挂机的话,无需另外一方进行人工干预,被挂机的一方仅简单回复200 OK就可以实现整个流程的完整性。
接下来,注册也是一样的道理,如果UAC需要对服务器端发送注册请求时,服务器端仅根据注册请求的信息来验证其身份即可,无需进行人工干预。服务器端验证UAC的信息,则会自动返回一个最终响应消息。
但是,如果是INVITE请求的话,则实现的流程完全不同。因为,如果呼叫方发起呼叫以后,对端话机振铃。在振铃时间内,如果被呼叫方不在工作台的话,电话一直振铃,需要花费一定时间来等待被呼叫方应答,接听电话,这时是需要人工干预来完成一个可靠性传输过程。当然,用户可以通过一些软交换呼叫路由的设置(SIP头添加alter-info:ring answer),终端电话(设置 Ring Answer)也可以实现呼叫的自动应答,这是另外一个话题。
通过以上例子,我们可以看到,其他的非INVITE都可以通过自动化的处理方式来实现,无需人工干预。因此,只有INVITE中带有ACK请求回复,而没有看到其他的请求中带ACK的请求回复。
05
ACK的其他讨论
因为篇幅的关系,笔者还没有完全讨论ACK的语法和完整的细节,因为ACK请求涉及了很多不同的场景,并且灵活性也很大,具体的细节建议大家查阅RFC3261。这里,我们简单讨论结果可能经常遇到的问题。
首先,在涉及到SIP Transaction中,大家需要注意,在INVITE的ACK是一个独立的transaction(刚才我们已经提及)。
其次,ACK在某些场景中可能被忽略,例如在无状态的服务器端对ACK的处理机制。根据RFC3261 8.2.7的规范,无状态UAS中必须忽略ACK请求。这个一定要注意。
最后,ACK的处理机制依赖于最终响应的类型。在UAC发起发起初始化请求,UAC需要对每个最终响应(300-699)发送一个响应消息,但是处理这个ACK的机制完全刷决于response的响应类型。在transaction进行处理时遵从具体的规则。关于规则的定义,读者可以查阅REFC3261的17章节。
06
总结
在本文章中,笔者首先介绍了ACK在INVITE呼叫流程中的构成和其必要性,然后笔者读者解释了ACK到底是请求还是一个响应的疑惑,接下来笔者讨论了非INVITE请求中没有带ACK的原因,最后,笔者讨论了ACK几个其他方面需要特别注意的地方。
通过以上讨论,笔者为读者提供了相对比较全面的ACK的了解。为了解释的便利,笔者在示例中仅使用了点对点的呼叫并没有涉及多个代理之间的呼叫和多个hop的处理。因此,对ACK的流程处理的讨论相对比较基础和简单。如果讨论讨论比较复杂的ACK处理机制,需要涉及其他的SIP的概念和内容,因为篇幅的关系不再做过多展开讨论,希望读者谅解,我们在未来的章节中会根据实际内容的安排做更加深入地讨论。