SIP协议详解(中文)-5

事务分为客户端和服务端两方。客户端的事务是客户端事务,服务器端的事务就是服务端事务。客户端事务发出请求,并且服务端事务送回应答。客户端和服务端事务都是逻辑上的概念,他们可以被无数部件所包含。特别是,他们在UA中和有状态的proxy服务器中存在。以第四节的例子来说明。在这个例子中,UAC执行客户端事务,它的外发proxy执行服务端事务。外发proxy同时也执行客户端事务,把请求发送到一个那发proxy的服务端事务。这个proxy也同时执行一个客户端事务,把请求发到一个UAS的服务端事务上去。这个在图四中比较明白:

+---------+         +---------+            +---------+         +---------+
|        +-+|Request |+-+     +-+|Request    |+-+    +-+|Request |+-+        |
|        |C||------->||S|     |C||------->    ||S|    |C||------->||S|        |
|        |l||         ||e|     |l||            ||e|    |l||         ||e|        |
|        |i||         ||r|     |i||            ||r|    |i||         ||r|        |
|        |e||         ||v|     |e||            ||v|    |e||         ||v|        |
|        |n||         ||e|     |n||            ||e|    |n||         ||e|        |
|        |t||         ||r|     |t||            ||r|    |t||         ||r|        |
|        | ||         || |     | ||            || |    | ||         || |        |
|        |T||         ||T|     |T||            ||T|    |T||         ||T|        |
|        |r||         ||r|     |r||            ||r|    |r||         ||r|        |
|        |a||         ||a|     |a||            ||a|    |a||         ||a|        |
|        |n||         ||n|     |n||            ||n|    |n||         ||n|        |
|        |s||Response||s|     |s||Response    ||s|    |s||Response||s|        |
|        +-+|<-------|+-+     +-+|<-------    |+-+    +-+|<-------|+-+        |
+---------+         +---------+            +---------+         +---------+
UAC                Outbound            Inbound               UAS
Proxy                Proxy
图4: 事务关系
无状态的proxy并没有客户端或者服务端的事务。事务是一边基于UA或者有状态的proxy,另外一边也基于UA或者有状态的proxy。在SIP事务范畴下,无状态的proxy是用作透明转发很有效。客户端事务的用处是用于从一个元素中接收一个请求,这个客户端是内嵌的(这个元素就是”事务用户”或者TU;它可以是一个UA或者有状态的proxy),并且可靠的把这个请求传送到一个服务端事务。

客户端事务也负责接收应答并且把应答转交TU处理,过滤掉重发的应答或者不允许的应答(比如给ACK的应答)。另外,在INVITE请求的情况下,客户端事务也负责产生给2xx应答的ACK请求。

类似的,服务端事务也负责从通讯层接收请求并且转发这个请求到TU。服务端事务过滤重发的请求。并且服务端事务从TU接收应答并且转发到通讯层来发送。在INVITE事务的情况下,它需要接收给非2xx应答的终结应答的ACK请求。

2xx应答和它的ACK请求通过特定的方式来接收和处理。这个应答只会被UAS重发,并且它的ACK只由UAC产生。由于呼叫者知道整个已经接收呼叫的用户集合,所以需要这种端到端的处理。由于这样的特别处理,2xx应答的重发是基于UA核心的,并非基于通讯层。类似的,给2xx应答的ACK处理也是由UA核心处理的,每个路径上的proxy仅仅转发这些INVITE的2xx应答以及他们的ACK。

17.1 客户端事务
客户端事务是通过维持一个状态机来提供服务的。

TU和客户端事务通过一个简单的接口进行通讯。当TU希望初始化一个新的事务,它创建一个客户端事务并且通过设置ip地址,端口和transport来把一个SIP请求交给它传送。然后客户端事务开始执行它自己的状态机。合乎规格的应答会从客户端事务传送给TU。

总共有两种类型的客户端事务状态机,根据TU传递的请求的方法不同来区分的。一个用于处理INVITE请求。这种状态机对应的是一个INVITE客户事务。另外一个是用来处理其他所有的非INVITE请求的。它对应的是非INVITE客户事务。对于ACK来说,是不存在客户事务的。如果TU希望送一个ACK请求,它直接交给通讯层进行通讯处理。

INVITE事务和其他事务是不同的,因为它的时间周期很长。通常,对于INVITE请求的应答来说,都需要人的参与,这样会导致在应答INVITE请求之前会有很长的延时。在三方握手(人,两方机器)的时候也会有很长的延时。在另一方面,其他请求的响应都是很快就完成的。因为其他非INVITE请求事务是双方的握手,TU能够立刻对非INVITE请求作出应答。

17.1.1 INVITE客户事务
17.1.1.1 INVITE事务概述
INVITE请求包含了一个三方的握手。客户端事务发送一个INVITE,服务端事务回送一个应答,客户端事务发送一个ACK。对于非可靠传输(比如UDP),客户端事务每隔T1重发请求,每次重发后间隔时间加倍。T1是一个估计的循环时间(round-trip time,RTT),缺省设置成为500ms。几乎所有的事务定时器都以T1为单位,并且调整T1的值也就调整了那些定时器的值。请求不会在可靠的通讯协议上重新发送。在接收到1xx应答以后,重发机制完全停止,并且客户端等待更进一步的应答。服务端事务可以发送附加的1xx应答,这个应答并非由服务端事务可靠传输。最后,服务端事务会发送一个终结应答。对于非可靠的传输协议,应答会间隔时间来重发,对于可靠的传输协议,它只发送1次。对于客户端事务所接收的每一个终结应答,客户端事务都发送一个ACK,用于终止应答的重发送。

17.1.1.2 正式的描述
INVITE客户端事务的状态机在图5中展示。初始状态,”calling”,必须保证TU是用INVITE请求来初始化一个新的客户端事务。客户端事务必须把请求发送到通讯层来进行发送(18节)。如果使用的是非可靠传输的通讯层,客户端事务必须启动一个定时器A并且由缺省值T1组成。如果是一个可靠的通讯协议,那么客户端事务不应当启动定时器A(定时器A控制请求的重发送)。对于任何通讯协议来说,客户端事务必须启动一个定时器B并且有着64×T1秒的缺省值(定时器B控制事务的超时)。

当定时器A触发了,客户端事务必须重发这个请求,把请求交给通讯层进行发送,并且重新设置定时器为2*T1。在传输层中重传的定义是指把刚才通过传输层发送的消息,再次交给传输层重新发送一次。

当定时器A在2×T1后触发了,请求必须再次重传(如果客户端事务依旧还是在这个状态的话)。这个处理必须持续下去,这样请求才能每重发一次以后定时器延时1倍。重发机制只有当客户端事务在”calling”状态的时候才能进行。

缺省的T1是500ms。T1是一个RTT的估计时间,是在客户端和服务端的一个事务处理的估计时间。节点可以(不推荐)使用更小的T1值,比如私有网络,并不接到INTERNET的网络可以设置小一点。T1也可以设置成为大一点的值,并且我们建议如果当我们知道RTT值比较大的时候(比如高延时的网络)应当设置T1成为大一点的值。不管T1如何取值,本节要求的重传机制要求的指数延时是必须使用的。

当定时器B触发的时候,如果客户端事务是依旧在”calling”状态,那么客户端事务应当通知TU发生了超时。客户端事务必须不能产生ACK。64×T1是和在不可靠通讯链路上传输7个请求的时间相同。

如果客户端事务在”calling”状态接收到一个临时应答,那么就把状态切换到”proceeding”状态,客户端事务不应当再次重新发送请求了。进一步说,临时应答必须传送给TU。在”proceeding”状态的任何临时应答都必须传送给TU。

当在”calling”或者”proceeding”状态的时候,如果接收到一个应答码是300-699的应答,那么就必须把状态切换到”Completed”。客户端事务必须把收到的应答转给TU,并且客户端事务必须传生ACK请求,即使通讯层是可靠传输的(在17.1.1.3节中有描述怎样根据应答创建一个ACK请求)并且把ACK交给传输层进行传送。ACK必须和原始请求发送到相同的地址,端口和用同样的transport。当客户端事务进入”Completed”状态的时候,应当开始一个定时器D,缺省值是在非可靠通讯上是至少32秒,在可靠通讯上是0秒。定时器D反应了服务端事务在非可靠传输的情况下,在”completed”状态维持的时间。这个是和INVITE请求服务端事务定时器H相同的,定时器H的缺省值是64*T1。不过,客户端事务不知道服务端事务使用的T1值,所以我们用绝对值32秒来代替T1用作定时器D的缺省值。

在”completed”状态下,受到的任何终结应答的重传都应当产生一个ACK应答到通讯层来重新发送,但是新近收到的应答却不能传送给TU。一个应答是否是重传的定义是根据这个应答是否和客户端事务按照17.1.3定义的规则匹配。



























图5: INVITE客户端事务

如果在客户端事务状态是”Completed”的时候,定时器D触发,那么客户端事务必须转到终结状态。当客户端状态是”calling”或者”proceeding”状态的时候,接收到一个2xx应答必须导致客户端事务进入”terminated”状态,并且应答必须交给TU处理。处理这个应答的方法依赖于TU是否是一个proxy核心还是是UAC核心。UAC核心会给应答产生ACK,proxy核心会转发一个200(OK)应答到上行队列。这个在proxy和UAC之间,对200(OK)的不同的处理是导致对应答的处理不在事务层进行的原因。

当客户端事务进入”terminate”状态以后,客户端事务必须立刻销毁。这样才能保证正确操作。原因是当给一个INVITE请求的2xx应答的不同处理;对于proxy转发的时候和对UAC处理ACK的时候是不一样的。因此,每一个2xx都需要交给proxy 核心(这样才能被转发),或者交给UAC核心(这样才能被ACK确认)。这期间没有事务层的处理。无论应答是否由通讯层收到,如果通讯层找不到匹配的客户端事务(用17.1.3的方式),那么应答就应当交给核心处理。这是由于与之匹配的客户端事务已经被第一个2xx应答所销毁,后续的2xx应当就匹配不成功了,于是就交给核心来处理。

17.1.1.3 构造ACK请求
本节定义了在客户端事务中构造ACK请求的方法。UAC核心为2xx应答产生ACK请求必须使用13节描述的方法,而不是用下边的方法。

在客户端事务中构造的ACK请求必须包括与原始请求相同的Call-ID, From, Request-URI头域值(就是说和在客户端事务发到通讯层的请求中的这些头域值相同)。在ACK请求中的To头域必须和被确认的应答的To头域值相同,因此通常和原始请求有所不同,不同点在增加了附加的tag参数。ACK必须包含一个单个的Via头域,并且必须和原始请求的最上边一个Via头域值相等。ACK的Cseq头域必须包含和原始请求的Cseq的序列号相同,但是方法参数应当是”ACK”。

如果INVITE请求的应答是有Route头域的,这些Route头域必须也在ACK中。这是确保ACK能够正确路由通过下行队列的无状态的proxy。

虽然请求可以包含一个包体,但是ACK的包体却比较特别,因为请求不能因为不能理解包体而拒绝这个请求。因此,我们不建议在给非2xx应答的ACK请求中放置包体,但是如果放置了,并且假设给INVITE的应答不是415应答,那么包体的类型应当严格和INVITE请求中定义的那样。如果是415应答,那么ACK的包体应当和415应答中的Accept列出的类型一致。

例如:有如下请求
INVITE sip:bob@biloxi.com SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKkjshdyff
To: Bob <sip:bob@biloxi.com>
From: Alice <sip:alice@atlanta.com>;tag=88sja8x
Max-Forwards: 70
Call-ID: 987asjd97y7atg
Cseq: 986759 INVITE

给非2xx终结应答的ACK请求应当是:
ACK sip:bob@biloxi.com SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKkjshdyff
To: Bob <sip:bob@biloxi.com>;tag=99sa0xk
From: Alice <sip:alice@atlanta.com>;tag=88sja8x
Max-Forwards: 70
Call-ID: 987asjd97y7atg
Cseq: 986759 ACK

17.1.2 非INVITE客户端事务
17.1.2.1 非INVITE事务概览
非INVITE事务并不使用ACK。他们只是简单的请求-应答的交互。对于非可靠的通讯来说,请求是间隔倍增T1的时间重新传输(直到间隔时间达到T2)。如果收到了一个临时应答,在非可靠通讯上,重传继续知道达到T2。只有当重传的请求收到的时候,服务端事务会重传其发出的最后一个应答,既可以是临时的应答也可以是终结应答。这就是为什么请求在收到一个临时应答之后还需要一直重传的原因;他们能够确保收到一个终结应答。

不像INVITE事务,非INVITE事务不需要对2xx应答做特别处理。UAC对一个非INVITE请求来说,只会产生一个单个的2xx应答。

17.1.2.2 正式的描述
在图6中讲述了非INVITE客户端事务的状态机。这个状态机和INVITE客户端事务的状态机非常像。

当TU用请求来初始化一个新的客户端事务的时候,首先进入的是“trying”状态。当进入这个状态的时候,客户端事务应当初始化一个定时器F,这个定时器F应当有一个初始值64×T1秒。这个请求必须交给通讯层来发送。如果使用的是非可靠传输的通讯协议,客户端事务必须还设置定时器E,初始值是T1。如果定时器E触发了,并且还是在”trying”状态,那么定时器需要设置成为MIN(2*T1,T2),并且重新发送;如果再次触发了,那么就再设置成为MIN(4*T1,T2),每次都是倍增,知道T2。这个过程会一直继续,直到重发的间距是T2为止。缺省的T2是4秒,并且它大概是一个在没有立刻响应的情况下,非INVITE服务端事务处理一个请求的时间。根据缺省的T1和T2,那么间隔就会是:500ms,1s,2s,4s,4s,4s以次类推。

如果定时器F触发了,并且客户端事务依旧是在”trying”状态,那么客户端事务应当通知TU这个超时,并且转入”terminate”状态。如果在”trying”状态的时候收到了一个临时应答,那么这个应答必须转给TU处理,并且客户端事务转到”proceeding”状态。如果在”trying”状态收到了一个终结应答(200-699的应答码),那么应答必须交给TU,并且客户端事务必须转到”Completed”状态。

如果定时器E在”Proceeding”状态触发了,那么请求必须交给通讯层进行传输,并且定时器E必须重新设置成为T2秒。如果定时器F在”Proceeding”状态触发了,那么必须通知TU超时了,并且客户端事务必须转到终结状态。如果在”Proceeding”状态的时候收到了一个终结应答(状态码200-699),这个应答必须发送给TU,并且客户端事务必须转到”Completed”状态。

一旦客户端事务进入”Completed”状态,对于非可靠传输的情况,客户端事务必须设置一个定时器K=T4秒,对于可靠传输的情况,设置定时器K=0秒。这个”Completed”状态维持的目的是为了缓冲可能会收到的其他重发的应答(这是为什么客户端事务在这里为非可靠传输维持一段时间的原因)。T4代表了网络在客户端和服务端事务中传输信息可能的时间。缺省的值T4=5秒。当应答具有相同的事务匹配的时候,根据17.1.3的判定,这个应答就是重发的应答。如果定时器K在这个状态被触发,客户端事务必须转到”Terminate”状态。

当事务进入终结状态,就必须立刻终止了。

17.1.3 客户端事务匹配应答
当客户端事务的通讯层收到一个应答,他必须决定是否由客户端事务来处理这个应答,这样17.1.1和17.1.2才能够正确执行。在Via头域的最上边的branch参数就是用来做这个的。一个应答和一个客户端事务匹配的话,就有两个条件:
1、    如果应答Via最上边的branch参数和创建这个客户端事务的请求的Via最上边的branch参数相同。
2、    如果Cseq头域的方法参数和创建事务的请求的方法相同。这是因为CANCEL方法的事务和源请求的事务不同,但是却有相同的branch参数所决定的。

如果一个请求是广播发送的,他可能从不同的服务器上得到不同的应答。这些应答的最上边的Via都有相同的branch参数,但是在To tag中是不同的。当收到了第一个应答,基于上边的规则,将会判定是这个客户端事务的应答,其他的应答将会视同为重发。这并不是错误的情况;多点传送SIP只是提供了一个根本的”寻找最接近的单点”服务的方法,这样就限定了只需要处理一个单个应答。详情参见18.1.1。



17.1.4 处理通讯错误。






























图6:非INVITE客户端事务
当客户端事务发送一个请求到通讯层发送的时候,如果通讯层报告发送失败,那么需要执行下列步骤。

客户端事务应当通知TU这个通讯失败,并且客户端事务应当直接转到”Terminate”状态。TU处理通讯失败的机制在附件[4]中描述。

17.2 服务端事务
服务端事务是用来传输请求到TU并且可靠的传输应答的。它是通过状态机来实现的。服务端事务是当请求到达的时候由核心创建的,事务的处理也是主要围绕着对应请求的(也就是说并非全部都是和对应请求相关)。

和客户端事务对应的,状态机依赖于是否接收的请求是INVITE请求。

17.2.1 INVITE服务端事务
INVITE服务端事务的状态图在图7表达。

当为一个请求创建了服务端事务的时候,服务端事务进入”proceeding”状态。除非服务端事务知道TU在200ms之内会生成临时或者终结应答(在这种情况下,TU可能会产生100Trying应答),他必须生成100(Trying)应答。这个临时应答是用来停止客户端重发请求的,这个可以避免网络风暴。这个100(Trying)应答是根据8.2.6节描述的步骤构造的,除此之外: 如果接收的请求头中的To头域没有tag标志,那么原来描述的可以增加tag标记,更改成为不应该增加tag标志。这个请求必须交给TU处理。

TU可以给服务端事务任意数量个临时应答。只要服务端事务在”proceeding”状态,每个临时应答都应当交给通讯层发送。这些临时应答并非被通讯层可靠的发送(他们并不重新发送临时应答)并且临时应答并不改变服务端事务的状态。如果在”proceeding”状态,收到一个请求的重发请求,那么就需要把从TU最近收到的那个临时应答重新交给通讯层发送一次。请求是否是重发的请求,是基于17.2.3来判定的匹配相同服务端事务的请求。

如果,在”proceeding”状态,TU发送了一个2xx应答给服务端事务,服务端事务必须把这个应答交给通讯层进行发送。这个并非由服务端事务进行重发;对于2xx应答的重发是由TU处理的。服务端事务必须转到”Terminated”状态。

当在”Proceeding”状态的时候,如果TU交给服务端事务一个300到699的应答,那么应答必须交给通讯层进行发送,并且状态机必须进入”Completed”状态。对于非可靠传输的情况,必须设置定时器G=T1秒,对于可靠传输的情况,不设置定时器G(=0的情况就是不设置)
这个是和RFC2543所不同的,2543要求应答都要重发,甚至在可靠传输的情况下。

当进入了”Completed”状态,必须为所有的传输,设置一个定时器H=64×T1秒。定时器H决定何时服务端事务取消重发应答。这个值和定时器B的取值一样,是等同于客户端事务会重试发送请求的时间。如果定时器G触发了,那么应答会交给通讯层再次发送,并且定时器设置成为MIN(2*T1,T2)秒。依此类推,当定时器G再次触发,那么定时器G的值会翻倍,直到T2。这个和非INVITE客户端事务的”trying”请求的重发机制是一样的。进一步说,当在”Completed”状态的时候,如果接收到重发的请求,服务端事务应当把应答交给通讯层再次发送。

当服务端事务在”Completed”状态的时候,如果收到了一个ACK请求,服务端事务必须转到”Confirmed”状态。因为定时器G会在这个状态被忽略,所有的应答重发都会被终止。

如果在”completed”状态的时候,定时器H触发了,就意味着没有收到ACK请求。在这个情况下,服务端事务必须转到”Terminated”状态,并且必须通知TU事务失败。































图7:INVITE服务端事务

设定”Confirmed”状态的目的是为了处理任何附加的ACK消息,这是由重发的终结应答所触发的。当进入这个状态,如果是在不可靠传输协议,那么就要设定一个定时器I=T4秒,如果是可靠传输协议,那么就设定I=0。当定时器I触发了,服务端事务必须转到”Terminated”状态。

当服务端事务状态处于”Terminated”状态,这个事务必须立刻销毁。和客户端事务一样,这是为了保证给INVITE的2xx应答的可靠性。

17.2.2 非INVITE服务端事务
对非INVITE服务端事务的状态机是在图8中表示。

 

当收到一个不是INVITE或者ACK的请求的时候,状态机会初始化成为”trying”状态。并且这个请求会交给TU处理。当在”trying”状态,任何重发的请求会被忽略。一个请求在通过17.2.3节的步骤,匹配现有的服务端事务,将被认为是重发的请求。

当处于”trying”状态,如果TU交给服务端事务一个临时应答,服务端事务应当进入”Proceeding”状态。这个应答必须交给通讯层进行发送。在”Proceeding”状态下从TU收到的任何应答都必须交给通讯层进行发送。如果一个重发的请求在”proceeding”状态下收到了,那么最近发出的一个临时应答应当再次交给通讯层进行重发。如果在”Proceeding”状态下,TU交给服务端事务一个终结应答(应答码是200-699),那么服务端事务必须进入”Completed”状态,并且应答必须交给通讯层进行发送。

当服务端事务进入了”Completed”状态,对于不可靠传输协议来说,必须设定一个定时器J=64×T1秒,对于可靠传输来说,设定为0秒(就是不设定定时器)。当在”Completed”状态下,当服务端事务收到了一个重发的请求的时候,服务端事务必须交给通讯层终结应答来重新发送。在”Completed”状态下,任何其他TU传递下来给服务端事务的终结应答都必须被抛弃。服务端事务保持这个状态直到定时器J触发,当定时器J触发了以后,服务端事务必须进入”Terminated”状态。

17.2.3 为服务端事务匹配请求。
当服务端从网络上收到一个请求以后,他必须和现有的事务进行判定。这个是根据下边的规则来判定的。

首先要检查请求中的Via头域的最上一个branch参数。如果他以”z9hG4bk”开头,那么这个请求一定是由客户端事务根据本规范产生的。因此,branch参数在该客户端发出的所有的事务中都是唯一的。根据下列规则我们可以判定请求是否和事务匹配:

1、    请求中的最上的Via头域的branch参数和创建本事务的请求的最上的Via头域的branch参数一样,并且:
2、    请求的最上的Via头域的sent-by参数和创建本事务的请求的最上的Via头域的send-by参数一样,并且:
3、    请求的方法和创建本事务的方法一样。这有一个例外,就是ACK,ACK对应的创建本事务的请求方法是INVITE。
这个匹配规则用于INVITE和非INVITE事务。

send-by参数被用于匹配过程,这是因为有可能存在无意/恶意的相同的不同客户端传来的branch参数。

如果最上的Via头域的branch参数不存在,或者没有包含那个”z9hG4bk”,那么就用下列步骤进行判定。这是为了和RFC2543进行兼容的。

如果是INVITE请求,并且这个INVITE请求的Request-URI,To tag,From tag,Call-ID,Cseq,和最上的Via头域都和创建事务的INVITE请求的这些字段匹配,那么这个INVITE请求就是匹配这个事务的INVITE请求。在这个情况下,INVITE就是创建这个事务的INVITE请求的一个重发。ACK请求在匹配创建事务的INVITE请求的Request-URI, From tag, Call-ID ,Cseq序列号(非方法字段), 最上的Via头域,并且To tag和服务端事务发出的应答的To tag相同,这个ACK就是这个事务的ACK。当这些头域比较完成,那么这个匹配也就完成了。在ACK比较中包含To tag的比较是为了在proxy上能够区别给2xx的ACK和给其他应答的ACK,这个proxy可能会转发全部的应答(这个会在某种罕见的情况下发生。特别是,当一个proxy分支一个请求,接着宕机了,应答会转发到别的proxy,这个proxy可能会终止转发多重应答到上行队列)。一个匹配INVITE请求事务的ACK请求,如果这个INVITE请求已经被前一个ACK请求所匹配,那么这个ACK请求就是上一个ACK请求的重发。




























图8: 非INVITE 服务端事务

对于所有的其他请求方法,如果请求的Request-URI,To tag,From tag,Call-ID, Cseq(包括Cseq中的方法字段),以及Via头域的最上值,都和创建服务端事务的请求想匹配,那么这个请求就是这个事务的匹配请求。匹配是基于针对每一个头域值的判定进行的。当非INVITE请求和现有事务匹配了,那么它就是创建这个事务的请求的一个重发。

由于匹配规则中包含了Request-URI,服务器不能匹配应答对应到事务。所以当TU传送了一个应答到服务端事务,它必须为这个应答指定传送到那个服务端事务。

17.2.4 处理通讯错误
当服务端事务发送一个应答到通讯层要发送的时候,如果通讯层报告发送失败,那么就需要执行下列的步骤:

首先,附件[4]的步骤需要执行,这就是说需要把应答发送一个备份的地点。如果这个也失败了,基于[4]中对失败的定义,服务端事务应当通知TU发送失败,并且把状态切换到终止状态。

18 通讯(transport)
通讯层负责请求和应答在网络上的实际传输。这包括了在面向连接的通讯方式下的请求和应答所使用的连接管理。

通讯层负责管理像TCP/SCTP之类通讯协议的长连接,或者在这些协议上的TLS连接,并且包括管理打开这些连接的使用者的管理。这包括了客户端或者服务端通讯层打开的连接,这样在客户端服务端通讯函数可以共享这些连接。这些连接采用一组用远端的地址,端口,通讯协议标志的索引来进行管理。当通讯层打开了一个连接,这个连接的索引就设置成为远端的IP,端口,还有打开这个连接的通讯层的实例 。当通讯层接收了一个连接,那么这个连接的索引就被设置成为连接方的源IP地址,port,还有通讯层的实例transport。注意,由于源端口port通常是临时创建的,但是由于通过附件[4]的步骤不能知道它是临时创建的还是配置的,所以通讯层被动接收的连接通常是不被重复使用的。这就是说,如果两个proxy再一个”peering”(点对点)的关系中,使用一个面向连接的通讯协议通常有两个连接要使用,每个都是自己作为主动方连接的。

我们建议在实现中,当发送(或者接收)完成最后一个消息之后,依旧维持这个连接一段时间(这段时间可以是实现自己定义的时间)。这段时间应当是至少等于本节点的事务从创建到结束的最长时间。这是为了让事务能够在他们所创建的同一个连接上完成(比如,在这个连接上完成请求,应答的处理,在INVITE的情况下的给非2xx的ACK应答等等)。这通常意味着至少64×T1秒(参见17.1.1.1中关于T1的定义)。不过,如果当本程序的TU使用的是一个比较大的定时器C(参见16.6节11步)的时候,也可以选取一个比较大的值。

所有的SIP元素都必须实现基于UDP和TCP的通讯。SIP元素还可以实现其他的协议。

要求UA支持TCP是对RFC2543的一个重要改进。这是由于需要处理更大的消息,就像接下来讲到的那样,必须使用到TCP协议。因此,即使是SIP元素不要发送大的消息,但是由于它可能收到大消息并且处理这些消息,所以,要求支持TCP。

18.1 客户Clients
18.1.1 发送请求
通讯层的客户端负责发送请求和接收应答。通讯层的用户把请求交给通讯层的实例进行处理,包括IP地址端口,通讯层实例,还有可能有多点广播的TTL。

如果请求的大小和MTU差是在200个字节以内的,或者它是大于1300字节的,并且路径MTU的大小是未知的,那么请求必须遵循RFC2914[43]控制阻塞的传输协议,比如使用TCP。如果这导致了Via最上边指定的通讯协议的改变,那么Via最上边的值就必须也随之改变。这使得在UDP传输上的消息的分割,并且也提供了大消息的传输阻塞控制。不过,在实现上,必须能够支持达到最大包大小的消息的处理。对于UDP来说,包含了IP和UDP头的大小是65535个字节。

在消息的大小和MTU之间的200个字节的”buffer”,提供了一个机制使得在SIP的应答中,可以超过请求的大小。比如在INVITE请求的应答中,增加了Record-Route头域值。有了这个额外的buffer,应答可以大概比请求大170个字节,而且在Ipv4上不用进行分块传输(假设没有IPSec,大概IP/UDP会使用30个字节)。当MTU是未知的时候,选取1300是基于假设Ethernet的MTU是1500字节的基础上。

如果SIP元素是因为消息大小的限制,所以基于TCP发送一个请求,并且消息如果不是因为大小的限制,会使用UDP来发送,并且如果建立连接产生一个ICMP 协议不支持的错误,或者导致TCP reset,那么这个元素就应当用UDP重试这个请求。这只是为了向后兼容RFC 2543针对不支持TCP的实现。在本规范以后的改动中,这部分内容会有修订。

如果客户端向多个地址发送请求,那么必须增加”maddr”参数到Via头域值上,并且这个参数值指定多个目的地址,对于Ipv4来说,应当增加”ttl”参数=1,IPV6的多点传送在本规范中没有定义,会在后续的标准中描述。

这些规则定义了SIP的多点传送。首要的目的是为了提供”寻找最接近的单点”服务(”single-hop-discovery-like”),这个服务将请求转发到一组类似的服务器,并且只需要处理其中任意一个服务器的应答。这个功能主要用于注册服务。实际上,基于17.1.3的事务处理规则,客户端事务会接收第一个应答,并且因为其他应答包含同样的Via的branch参数,而视这些应答为重发应答。

在请求发送嵌,客户端通讯层必须在Via头域中增加一个”sent-by”栏。这个字段包含了一个IP地址或者主机名,端口。我们推荐使用FQDN方法描述这个主机名。这个字段在某些特定情况下,用于发送应答。如果端口不存在,缺省的值依赖于通讯协议。对于UDP,TCP和SCTP来说是5060,TLS是5061。

对于可靠传输协议,应答通常简单的通过连接发送,并且这个连接是收到对应请求的连接。因此,客户端传输层必须准备在发出请求的同一个连接上接收应答。在出现错误的情况下,服务端可能会尝试新建立一个连接来发送应答。为了能够处理这种情况,通讯层必须准备接
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值