SACK是一个TCP的选项,来允许TCP单独确认非连续的片段,用于告知真正丢失的包,只重传丢失的片段。

传统情形

下图罗列了一个客户端与服务器的TCP链接,时间在纵向上从上到下:

客户端给服务器发送了一些请求,服务器将回复分隔成为四个TCP Segments,并将其作为回复返回给客户端。然而,第二个回复丢失了,没有达到主机,下面对整个过程进行一些梳理(下面每一步对应上图一个圆圈):

  • 返回Segment 2丢失了。
  • 客户端接收到了Segment 3, 检查Sequence Number,客户端认识到这个段是失序的,客户端重传了一个冗余请求来告诉服务器,Segment 1之后任何可靠数据仍旧未被接收。
  • 服务器没有注意到有些事情错了,它仍旧在发送Segment 4,客户端发现仍旧未改善,所以重复发送冗余ACK给服务器。
  • 服务器接收到客户端的第一个冗余的ACK,发现仍旧需要重传Segment 2。
  • 客户端成功接收,并ACK了另外三个段。

SACK

你可能注意到设计是没有效率的,尽管只有Segment 2丢失了,但是服务器仍旧需要重传Segment 3和Segment 4,因为客户端没有确认这两个段。

SACKs通过允许客户端说“我只有Segment 1是有序的,但,我也接收到了Segment 3和Segment 4”,这允许服务器仅仅重传丢失的包。

在TCP开始链接时,他们将会协商是否支持SACK,如果两端都支持,就可能会被使用,让我们看看下面这个例子:

对应以下几步:

  • Segment 2丢失了。
  • 客户端发现Segment 1和Segment 3之前丢了一个段,发送了一个带SACK的冗余ACK。
  • 客户端接收到了Segment 4,发送了一个冗余ACK带SACK 3, 4。
  • 服务器重传Segment 2。
  • 客户端接收到后确认Segment 4。