定义
TCP
TCP,即传输控制协议(Transmission Control Protocol)。
特点
- TCP是面向连接的运输层协议。在传送数据前必须先建立TCP连接,在传送数据完毕后,必须释放已经建立的TCP连接。
- TCP连接只能有两个端点,只能是点对点的。
- TCP提供可靠交付的服务。
- TCP提供全双工通信。
- 面向字节流。
首部
总长度:20+4n字节。
- 源端口:2字节。发送方进程端口。
- 目的端口:2字节。接收方进程端口。
- 序号:4字节。表示本报文段所发送的第一个字节的序号,每一个字节都有序号。序号范围为,共个序号。的下一个序号为0。
- 确认号:4字节。即期望收到对方下一个报文段的第一个数据字节的序号。若确认号为N,表示序号到N-1为止的所有数据都已经正确收到。
- 数据偏移:4位。TCP报文段的首部长度,单位为4字节,4位表示的最大值为15,因此首部最大长度为4 * 15=60字节。
- 保留:6位。保留今后使用,置0。
- 紧急URG:1位。为1时表示紧急指针有效 。需要配合紧急指针使用。
- 确认ACK:
- 推送PSH:
- 复位RST:
- 同步SYN:
- 终止FIN:
- 窗口:2字节。这里的窗口表示发送方的接收窗口大小,窗口范围为。
- 检验和:
- 紧急指针:
- 选项:长度可变,最大为40字节。
- 最大报文段长度MSS:4字节。表示每一个TCP报文段中的数据字段的最大长度。
- 窗口扩大:3字节。
- 时间戳:10字节。
- 选择确认SACK:
可靠传输的工作原理
停止等待协议
无差错
A发送分组后,暂停发送,等待B的确认。在收到B的确认后,继续发送下一个分组。
出现差错
发送完分组后A会为发送的分组设置一个超时计时器,如果超过了重传时间仍未收到B的确认,就认为发送的分组丢失了,重传该分组。
- A发送分组后要保留已发送的分组的副本,直到收到相应的确认后才能清除分组副本。
- 分组和确认分组都需要编号
- 超时计时器的重传时间应当比数据在分组传输的平均往返时间更长一点
确认丢失和确认迟到
确认丢失:如果B收到了A的分组M1,但发送的确认分组丢失了,A没有收到B的确认分组,因此进行超时重传。
此时B再次收到A的同一个分组M1,此时B将:
- 丢弃重复的分组M1
- 发送M1的确认分组
确认迟到:如果B收到了A的分组M1,但发送的确认分组R1因为网络原因迟到了,A没有收到B的确认分组,因此进行超时重传。
此时B再次收到A的同一个分组M1,此时B也将: - 丢弃重复的分组M1
- 发送M1的确认分组R2
之后因为网络原因迟到的R1到达A,但R2已经确认了M1,因此A将什么都不做。
信道利用率
倘若使用单个分组发送-确认的方式,信道的利用率U为:
:发送分组需要的时间。
:往返时间。
:处理时间和。
如果RTT远大于,信道的利用率就会很低。因此需要使用流水线传输:连续发送多个分组,而不必每发完一个分组就等待该分组的确认。
连续ARQ协议
发送方有一个发送的滑动窗口,可以将窗口内的分组连续发送,在接收到确认后,就可以将窗口向前移动,继续发送分组。
接收方采用累积确认:
接收方在收到了几个分组后,只对按序到达的最后一个分组发送确认,而不是每个都发送确认。
比如:A发送了1、2、3、4、5,B接收了1、2、4、5,就发送2的确认,A接收到2的确认,就重传3、4、5(即Go-Back-N,回退N)。
可靠传输的实现
滑动窗口
发送窗口
发送方A维护一个发送窗口:在没有收到B的确认的情况下,A可以将窗口内的数据都发送出去。
发送方的数据为四个部分:
- 已发送并收到确认:这部分数据已经安全送达,窗口已经移过它们。
- 已发送但未收到确认:数据已经发出,但还在路上或正等待对方回复。
- 允许发送但尚未发送:窗口内剩下的名额,随时可以发送。
- 不允许发送:超出窗口范围的数据,在窗口移动前绝对不能发送。
发送窗口 = 2(已发送未确认) + 3(允许发送未发送)
还没有收到确认的数据都必须暂时保留,以便用于超时重传。
收到B的确认后,A的发送窗口向前滑动。
接收窗口
接收方B维护一个接收窗口:表示接收方目前准备好接收并处理多少数据。它的主要作用是防止发送方发送速度过快,导致接收方的缓冲区溢出。
接收方的数据为三个部分:
- 已接收并已确认:数据已成功处理,窗口已移过。
- 允许接收的区域:这就是接收窗口。只有落在这个范围内的序号,接收方才会接受并放入缓冲区。
- 不允许接收的区域:超出窗口范围的数据,即使送达也会被直接丢弃。
工作过程
- 建立连接:接收方告诉发送方接收窗口的大小(rwnd)。发送方把发送窗口设置为和接收窗口一样大。
- 发送数据:发送方开始发送数据。发送窗口内一部分数据变为已发送未确认,一部分数据为允许发送未发送。
- 接收与确认:接收方成功接收部分数据,并向发送方回复确认消息ACK(确认号,新的接收窗口大小)。
- 窗口向前滑动:发送方收到确认消息ACK后,发送窗口向前移动。
超时重传
发送方在规定的时间内没有收到确认就要进行重传,因此超时重传的时间十分重要。
TCP采用了一种自适应算法来计算超时重传时间RTO(RetransmtssionTime-Out)。
根据当前报文段的RTT,可以不断计算出一个新的(平滑的往返时间,Smoothed):
己成为建议标准的 RFC 6298推荐的值为0.125。
显然超时重传时间应该稍大于,因此再计算一个(RTT 的偏差的加权平均值):
的推荐值为0.25。
在有了和后,我们就能得到的计算公式:在有了超时重传时间时,我们还需要考虑重传带来的问题:
- 假设主机发送了一个报文段,超时计时器到时了还没有收到确认,因此进行重发。经过一段时间,收到了确认,但此时无法判断是一开始的报文段还是重传的报文段的确认,也就无法确认RTT是从此时到第一次发送还是从此时到重传。
- 根据1,不使用重传的RTT,假如网络突然出现了严重堵塞,RTT变得极大,此时RTO对于RTT来说很小,如果不更新RTO,接下来的每个报文段都肯定会重传,并且以很小的间隔进行重传,使得网络更加拥堵。
因此有Karn算法:
- 在计算时,只要报文段重传了,就不用这个报文段进行RTO的计算。
- 报文段每重传一次,就把RTO增大为原来的2倍,直到不再重传才继续使用上面的公式计算新的RTO。
选择确认
假设发送方一次性发了好几个报文段,结果只有第一个报文段丢失了,接收方其他都收到了。
如果采用传统的累计确认,接收方回复的ACK不变,结果后面已经收到的报文也会被全部重传一遍。
通过在首部选项添加SACK字段,可以告诉发送方已经收到的不连续数据块的边界,如。
流量控制
主要关注两个主机间的问题,防止发送方发送太快,接收方来不及处理。
滑动窗口
在建立连接和发送确认时,接收方会在首部窗口字段中告诉发送方接收窗口的大小。发送方的发送窗口随接收窗口的大小变化,即。rwnd为0时代表不允许发送方发送。
持续计时器
假设接收方发送了rwnd为0的确认报文段之后不久,接收方的缓冲区可用了,于是发送了rwnd不为0的确认报文,但这个报文丢失了,此时发送方不发送报文,接收方又在等待新的报文,产生了死锁。
因此TCP设有持续计时器,只要发送方接收到rwnd为0的报文段时,就启动该计时器。当计时器超时时,就发送一个零窗口探测报文段,然后重置计时器,直到收到rwnd不为0的报文段。
糊涂窗口综合征
当发送方发送数据很慢或接收方处理数据很慢时,TCP窗口很小,每次发送的报文段中数据部分都很小,大部分网络都用来发送首部了,网络效率很低。
- 发送方发送效率太低:发送方输入数据很慢,导致每次只发送数据部分很小的报文段。
- Nagle算法:
- 对于第一个字节,直接发送。
- 等到收到上一个报文段或发送缓冲区达到了最大报文段长度MSS,才将发送缓冲区中的数据一次性发出。
- 接收方处理效率太低:每次只能处理几个字节,导致接收缓冲区只有几字节,因此接收窗口和发送窗口也很小。
- Clark算法:
- 当接收缓冲区的剩余空间达到了总空间的一半
- 当接收缓冲区的剩余空间达到了MSS的大小
- 才向发送方发出确认报文更新rwnd大小,否则rwnd为0
拥塞控制
主要关注整个网络的的问题,防止网络中的路由器过载。
cwnd:拥塞窗口(congestion window)。
ssthresh:慢开始门限(Slow Start Threshold)。
慢开始
- 初始拥塞窗口cwnd设为1或2个发送方最大报文长度SMSS。
- 每收到一个ACK,cwnd+=1,一次发送了cwnd个报文段,因此每经过一个RTT,cwnd*=2。
- 当cwnd≥ ssthresh时,转向使用拥塞避免算法。
这里的窗口以一个报文段为单位。
拥塞避免
- 每收到一个ACK,cwnd+=1/cwnd,每经过一个RTT,cwnd+=1。(即加法增大AI,Additive Increase)
快重传
- 接收方如果发现发生了丢包(收到了乱序的的报文段),每收到一个报文段就发送带有ACK的确认。
- 发送方如果连续收到4个相同ACK的确认(3个冗余ACK),就不等待超时计时器超时,立即进行重传。
快恢复
- 在快重传发送方收到4个相同ACK并重传后。
- ssthresh = cwnd /2。(即乘法减小MD,Multiplicative Decrease)。
- cwnd = ssthresh(或)。
- 开始执行拥塞避免算法。