ACK的特点
- ACK仅用于对INVITE消息的最终响应进行确认
- ACK的CSeq的号码必须和INVITE的CSeq号码相同,这是用来保证ACK对对哪一个INVITE进行确认的唯一标志。另外CSeq的方法会改为ACK
- ACK分为两种
- 失败请求的确认;例如对4XX, 5XX请求的确认。在对失败的请求进行确认时,ACK是逐跳的。
- 成功的请求的确认;对200的确认,此时ACK是端到端的。
- ACK一般不会带有SDP信息。如果INVITE消息没有带有SDP,那么ACK消息中一般会带有ACK
ACK与事务的关系
- 如果请求成功,那么后续的ACK消息是单独的事物
- 如果请求失败,那么后续的ACK消息和之前的INVITE是属于相同的事务
逐跳ACK VS 端到端ACK
逐跳在英文中叫做: hop-by-hop端到端在英文中叫做:end-to-end
ACK如何路由
ack是序列化请求,所谓序列化请求,是指sip to 字段中已经有tag。有to tag是到达对端的唯一标志。
没有to tag请求称为初始化请求,有totag称为序列化请求。
初始化请求做路径发现,往往需要做一些数据库查询,DNS查询。而序列化请求不需要查询数据库,因为路径已经发现过了。
实战场景:分机A, SIP服务器S, 分机B, A呼叫B,详细介绍一下到ACK的过程。
- 分机A向SIP服务器S发送请求:INVITE B
- SIP服务器
- 首先在数据库中查找B的实际注册地址
- 修改Contact头为分机A的外网地址和端口。因为由于存在NAT, 分机A一般不知道自己的公网地址。
- record_route
- 将消息发送给B
- 分机B:
- 收到来自SIP服务器的INVITE消息
- 从INVITE中取出Contact, 获取对端的,其实也就是分机A的实际地址
- 如果所有条件都满足,分机B会向SIP服务器发送180响应,然后发送200响应
- 由于180响应和200响应和INVITE都属于一个事务,响应会按照Via的地址,先发送给SIP服务器
- SIP服务器:
- SIP服务器会首先修改180响应的Contac头,把分机B的内网地址改为外网地址
- SIP服务器根据Via头,将消息发送给分机A
- 对于200 OK的消息,和180的处理是相同的
- 分机A:
- 分机收到180消息后,从Contact头中能够获取分机B的外网地址
- 分机A在发送ACK时,request url地址是分机B的地址,但是由于sip服务器的record_route动作首先会将消息发送给SIP服务器,SIP服务器会按照request url的地址,将ack发送给分机B。
ACK的路由不需要做数据库查询,ACK的request url一般是对端UAC的地址。在存在route头时,ACK会按照route字段去路由。
ACK丢失了会怎样?
如果被叫在一定时间内没有收到ACK, 那么被叫会周期性的重发200OK。如果在超时的时候,还没有收到ACK, 就发发送BYE消息来挂断呼叫。很多呼叫在30秒自动挂断,往往就是因为丢失了ACK。
那么ACK为什么会丢失呢?可能有以下的原因,大部分原因和NAT有关!
- SIP服务器没有做fix_nat_contact, 导致主叫可能不知道实际被叫的外网地址
ACK与媒体流的关系
并不是说被叫收到ACK后,媒体流才开始。往往在180或者183时,双方已经能够听到对方的声音了。