1. TCP为每个连接维护4个计时器: 超时重传计时器, 坚持计时器, 存活计时器, 2MSL计时器. (Page.297)
2. TCP的超时时间采用指数退避机制, 每次超时时间是上一次的2倍, 上限为64s. (Page.299)
3. TCP的RTT计算从发送一个数据开始, 以收到"覆盖"这个数据的最后一个字节的ACK为结束. (Page.299)
4. 原来估算超时重传时间RTO的计算方式为:
R := aR + (1-a)M M为最后一次获得的RTT时间, R为原来保存的估算RTT, a的建议值为0.1
RTO := bR b的建议值为2.
这种计算方式有一个缺点: 在遇到RTT有较大波动时(即M变化较大), 这样计算RTO的变化可能跟不上RTT的变化, 可能重传过快反而加大了网络的压力. (Page.299, 300)
5. 新的RTO计算方式为:
Err := M - A M为最近一次测得的RTT, Err是偏差
A := A + gErr A为估算RTT, g的建议值为0.125(1/8)
D := D + h(|Err| - D) D为估算均方差, h建议值为0.25(1/4)
RTO := A + 4D
这样的计算方式有两个好处: 能够结合平均RTT和变化差异计算RTO; 以上公式使用定点小数计算, g和h的值可以用移位代替乘法. (Page.300)
6. 出现重传时, 所测量得的RTT不加入RTO的计算, 并且在发送下一个数据时使用的RTO是本次重传的最后一次使用的RTO, 直到能够不用重传就成功获得ACK才继续使用测量得到的RTT计算RTO. (Page.301)
7. socket debug选项只支持TCP, 需要在程序中打开, 不需要root权限. (Page.301)
8. TCP一般只维持一个RTT计时器, 即如果启动RTT计时使用的是A报文, 那么在收到包含A报文的确认前, 不能再启动RTT计时器. (Page.303)
9. RTT和SYN超时计时, 延迟确认一样, 使用"内部统一计时器触发"来计算时间, 内部计算的RTT为测量时间内计时器的触发次数*500ms. 如果一个RTT的实际时间是550ms, 那么内部计算得出的RTT可能为500ms(计时器触发一次), 或者1000ms(计时器触发两次). (Page.303)
10. 条目5中的A和D需要初始化, 并且有两次不同的初始化. 第一次初始化发生在在第一次发送SYN时, A和D分别被初始化为0和3, 并且RTO的计算公式为RTO:=A+2D, 即SYN的第一次超时重传时间为6s(注意由于触发机制实际超时时间为5.5s~6s), 但是这个公式仅使用一次, 在第一次SYN超时后, 公式恢复为RTO:=A+4D, 所以SYN的第二次超时时间为(0+4*3) * 2 = 24s(后面乘以2是因为指数回避). 第二次初始化发生在第一次成功接收ACK(没有重传), 这时通过一下公式初始化A和D:
A := M + 0.5
D := A / 2 (Page.305)
11. 快重传算法的原理是: 在连续收到3个重复的ACK(即总共收到4个相同的ACK), 就马上重传这个ACK的确认号指向的数据, 而不用等待RTO时间. 注意快重传算法并不影响后续数据的发送, 只要窗口仍然允许, 那么就会继续发送后续数据, 因为对方会保存乱序的数据一段时间, 但是收到乱序的数据会马上触发ACK的发送, 不会延迟. (Page.309)
12. 拥塞避免和慢开始两个算法结合在一起使用, 通过为每个链接维护两个变量实现: cwnd--拥塞窗口大小, ssthresh--慢开始阀值. 开始时cwnd被初始化为一个报文大小, sshresh被初始化为65535. (Page.310)
13. 当发生拥塞时, ssthresh设为当前窗口值(min(cwnd, rwnd))的一半, 但是最小值为两个报文. 如果拥塞是由超时引起的, 那么cwnd被设为1个报文大小并执行慢开始, 如果因为重复ACK, 那么执行快恢复算法. (Page.310)
14. 当cwnd < ssthresh时, 那么cwnd使用慢开始算法指数增长(每确认一个报文就增加一个报文大小), 如果cwnd > ssthresh, 那么cwnd使用拥塞避免算法线性增长(每确认一个报文cwnd增加MSS^2/cwnd), 如果cwnd == ssthresh, 既可以使用慢开始, 也可以使用拥塞避免. (Page. 310)
15. 当TCP收到一个乱序报文, 会马上生成一个ACK指向未乱序前期望收到的数据的序号, 并马上发送不会延迟. (Page.312)
16. 一般来说收到1到2个重复的ACK(不计一开始的第一个"真正"的ACK)是有可能的, 但是如果连续收到3个重复的ACK, 那么可以认为已经丢失报文可以使用快重传发送该报文了. (Page.312)
17. 快恢复算法的细节是: 出现重复ACK时, ssthresh被设为当前窗口值的一半(条目13), 而cwnd设为sshresh+3个报文, 并在条件允许的情况下继续发送报文, 如果还继续收到重复ACK, 那么cwnd继续扩大, 每收到1个重复ACK, cwnd扩大1个报文大小, 并在窗口值(min(cwnd, rwnd))允许的条件下继续发送报文. 直到成功收到新的ACK, cwnd被设为ssthresh. 这么做是更具这么一个假设: 除了丢失的报文(ACK指向的数据), 后面的数据都被正确收到了, 所以这些数据已经在对方主机上而不在网络上, 因而也不会造成网络拥塞, 所以可以进一步扩大cwnd, 增强吞吐量. (Page.312)
18. 快恢复只与快重传结合使用, 如果重传是由于超时引起的, 那么仍使用慢启动算法. 因为出现超时的时候, 网络的拥塞已经非常严重(因为大量的ACK都没了才会超时, 严重丢包), 所以要用慢启动减轻网络负担; 而如果只是出现多个重复ACK, 说明网络并不是非常拥塞(否则也不会收到多个ACK), 所以可以使用快回复. (Page.313)
19. 对于路由表上的非默认条目, 那么会保留上一次链接的部分信息(A, D, ssthresh), 一边在下一次建立链接时可以使用这些值来初始话, 可以加快收敛. (Page.316, 317)
20. TCP收到源抑制ICMP时, cwnd设为1个报文大小开始慢启动, 但是ssthresh不变. 收到不可达ICMP时会保存这个错误但是不做处理, 直到TCP超时, 则会返回这个错误("No route to host"). (Page.317)
21. TCP发送超时为9分钟. (Page.317)
22. 当TCP超时重传时, 不必再保持原来数据的分段分开发送, 而是把数据合并成不超过MSS的报文一起发送. (Page.320)