TCP一致被认为是可靠的传输层协议,但是TCP为什么可靠呢?我们在开发项目,无论是业务项目还是中间件等基建项目,如何才能做到可靠呢?这篇文章主要整理了TCP围绕可靠传输的所有核心设计。
什么是可靠传输
首先,这里定义一下什么是可靠传输,这里笔者找到了两个方向创建了一个3*5的认知矩阵。
从传输这件事的完成情况角度思考,有三个对可靠的定义:1)可以传输(feasibility);2)遇到异常的时能克服(robust);3)传输十分高效(efficiency);4)传输的有质量(quality);5)传输有公德心的不破坏网络环境(morality);

从传输这件事的参与者角度思考(整个网络体系,和数据),可靠的传输应该是在数据角度和网络角度都可靠。

当然这两者相乘,3*5,就可以定义一个最多15个细节角度的认知架构,来分析 TCP是通过什么设计来完成的什么角度的可靠。当然这个有15个元素的矩阵可能并不能完全被填满,也可能相互有重复。但这两个树状图给了分析这个问题的一个结构化的框架来定义和认知”可靠“这件事。
如何做到可靠传输
核心一张图
通过把这个矩阵简化,匹配上解决响应问题的TCP设计,笔者呕心沥血形成了下面这张大图。这张脑图里有TCP全部的核心设计,这张图有两种看法:第一种看法是看看是不是有不了解的知识点:nagle algorithm是什么,tcp的cwnd是什么等等;第二种看法是在对TCP各种核心机制的有基本认识的基础上按照达成可靠的认知图谱快速串联所有机制。
!!!!!!!!!!!!!!本文的核心是下图

TCP防止丢失与确认送达
这里选择TCP防止信息丢失这个点把TCP的各种算法进行串联。为了解决信息丢失问题TCP采用了各种算法,其复杂或者说成熟程度可见一斑。
(1)最容易想到的ack确认机制:ACK基本是最常见的确认送达的机制了,消息队列中就很常见比如rabbitmq中就有出现;TCP中为了节约效率使用累计ack也就是accumulated ack来节约信息的传递;
(2)ACK中包含的信息有两种:确认累计收到数据和fast-retransmission。
- 确认累计收到数据:TCP通过发送最后一个是确认收到截至到编号XXX+1的segments,比如当收到了编号10的segment,接收方会返回一个ack11告知发送方。
- fast-restransmission:但当接收方收到了编号9,11,12但就是少了10,接收方可以通知发送方专门补充10,通知的方式不是通过设置header flag而是多次ack 10给发送方,当发送方收到多个ack10时就会意识到中间10的片段丢失了并会快速重发。
(3)ack也需要确认:ack本身是不容易再次被ack确认,不然ack确认ack有需要确认第二个ack就会陷入死循环;但是ack真的丢了时对方没有收到ack里的信息会不会造成严重后果呢,答案是是的。这里有两种情况。
- ack是为了确认某一个data segment被接受到的,ack丢失会会使得对方ack等待超时而重新发送并判断网络状态差调整发送速率,这里就是TCP的RTO timeout和retransmission机制;
- 丢失的ack是为了重新调整之前设置为0的advertised window的:当接收方buffer满时会把advertised window设置为0使得对方不能再发送消息,但当接收方处理完数据之后需要再次重置window为正常水平,这里就需要ack nextSegmentNumber并在header option里设置window size。那这个丢失了怎么办呢,对方没收到window变化在等window重启的ack,但这个ack丢了发送方又不知道(双方死锁了)。为了解决这个问题,TCP新增了一个persistent timer给接收方,timer按照指数型(有上限)的基础上进行click,每次lick信息接收方都会发出window probe(一个带有一个字节数据的segment发送给对方,等待对方ack中的window)。这就是TCP中的persistent timer和window probe。
所以可以看到TCP为了防止信息丢失采用了三种机制:(1)普通数据的accumulated ack;(2)中间缺失片段的fast-retransmission;(3)特殊ack(window size)的persistent timer和window probe;