003--TCP 知识点总结
[TOC]
- TCP/IP在计算机分层中的那层
- TCP/IP和UDP/IP的区别
- TCP拥塞策略
- HTTPS的安全策略是怎么实现的
-
OSI七层 TCP/IP五层
应用层
表示层
会话层
传输层(TCP)
网络层(IP)
数据链路层
物理层 -
TCP/IP五层模型
应用层
传输层(TCP)
网络层(IP)
数据链路层
物理层
TCP握手
三次握手建立连接
为什么是三次握手不是两次?
为了解决超时导致重复建立的问题。如果是两次握手会出现的问题。客户端发送SYN请求建立连接时,如果网络发生延迟超时后客户端会重复发送SYN消息,服务器接收到第二次发送的建立连接请求,返回确认信息,连接建立完成。第一次发送SYN建立连接请求经过一段时间后到达服务器,服务器会认为客户端要建立新的连接,会重新发送应答响应。这就导致了重复建立连接的情况。
四次挥手断开连接
为什么是四次挥手?
关闭连接,需要双向关闭才算真正的关闭。客户端发送FIN请求切断连接,服务器端发送ACK应答切断,当前连接处于半关闭状态。服务器端向客户端发送FIN请求切断连接,客户端返回ACK应答请求,此时连接才真正的关闭。
TCP传输
通过序列号和确认应答提高可靠性
当客户端发送数据之后需等待对端的确认信息。如果收到确认应答,表示数据成功发送到对端。如果在一定时间内没有收到确认应答,则认为数据已丢失,需要重新发送。未收到应答消息,两种情况数据丢失,另一种是应答消息丢失。应答信号丢失,重新发送对端就会重复接收相同的数据,为了解决目标端重复接收相同数据,可以通过为发送数据的每个字节标上序号,接收端收到数据根据首部序号和长度,将下一次应该的接收的序号作为应答返回出去。这样就可以通过序列号和确认应答,实现可靠传输。
重发超时如何确定
上面提到客户端在超过一定时间没有接收到应答消息会进行数据重发。那么这个超时时长是多少呢?理想状态下,找到一个小的时间,确保应答消息在该时间段中可以返回,但是不同的网络环境下这个时间会发生变化。TCP为了在不同网络环境下都能提供高性能通信,为此每次发送数据都会计算往返时间及其偏差。超时时间比这个往返时间与偏差的和稍大一点的时间。
面向字节流
TCP在建立连接时,会确认一次数据包传输的单位。称之为“最大消息长度(MSS)”。建立连接客户端SYN消息中携带一个MSS值,服务器的返回的SYN中也会携带一个MSS值,最终会选择两者中较小的按个作为数据包的传输单位。
滑动窗口流量控制
TCP以一个MSS大小传输数据,往返时间越长,网络的吞吐量也差。为了解决这个问题,引入了窗口的概念。发送端在发送一个段后不需要等待应答信息进行发送数据。窗口大小是指无需等待应答消息继续发送数据的最大值。窗口提供了缓存机制,实现对多个段同时应答的功能。
TCP拥塞策略
TCP 的拥塞控制主要是四个算法:1)慢启动;2)拥塞避免;3)拥塞发生;4)快速恢复。
整个拥塞控制的过程大致如下图所示:
慢启动算法
慢启动的算法如下(cwnd 全称 Congestion Window):
-
1)连接建好的开始先初始化 cwnd = 1,表明可以传一个 MSS(Max Segment Size)大小的数据。
-
2)每当收到一个 ACK,cwnd++; 呈线性上升。
-
3)每当过了一个 RTT,cwnd = cwnd*2; 呈指数上升。
-
4)还有一个 ssthresh(slow start threshold),是一个上限,当 cwnd >= ssthresh 时,就会进入「拥塞避免算法」。
所以,我们可以看到,如果网速很快的话,ACK 也会返回得快,RTT 也会短,那么,这个慢启动就一点也不慢。
拥塞避免算法
前面说过,还有一个 ssthresh(slow start threshold),是一个上限,当 cwnd >= ssthresh 时,就会进入拥塞避免算法。一般来说 ssthresh 的值是 65535 字节,当 cwnd 达到这个值时后,算法如下:
- 1)收到一个 ACK 时,cwnd = cwnd + 1/cwnd。
- 2)当每过一个 RTT 时,cwnd = cwnd + 1。
这样就可以避免增长过快导致网络拥塞,慢慢的增加调整到网络的最佳值。很明显,是一个线性上升的算法。
拥塞状态时的算法
当丢包的时候,会有两种情况:
- 1)等到 RTO 超时,重传数据包。TCP 认为这种情况太糟糕,反应也很强烈。
sshthresh = cwnd/2。
cwnd 重置为 1。
进入慢启动过程。
2)快速重传(Fast Retransmit)算法,也就是在收到 3 个 duplicate ACK 时就开启重传,而不用等到 RTO 超时。
TCP Tahoe 的实现和 RTO 超时一样。
TCP Reno的实现是:
cwnd = cwnd/2。
sshthresh = cwnd。
进入快速恢复算法(Fast Recovery)。
上面我们可以看到 RTO 超时后,sshthresh 会变成 cwnd 的一半,这意味着,如果 cwnd<=sshthresh 时出现的丢包,那么 TCP 的 sshthresh 就会减了一半,然后等 cwnd 又很快地以指数级增涨爬到这个地方时,就会成慢慢的线性增涨。我们可以看到,TCP 是怎么通过这种强烈地震荡快速而小心得找到网站流量的平衡点的。
快速恢复算法
TCP Reno 这个算法定义在 RFC5681。快速重传和快速恢复算法一般同时使用。快速恢复算法是认为,你还有 3 个 Duplicated Acks 说明网络也不那么糟糕,所以没有必要像 RTO 超时那么强烈。注意,正如前面所说,进入 Fast Recovery 之前,cwnd 和 sshthresh 已被更新:
- cwnd = cwnd /2
- sshthresh = cwnd
然后,真正的 Fast Recovery 算法如下:
- cwnd = sshthresh + 3 * MSS (3 的意思是确认有 3 个数据包被收到了)。
- 重传 Duplicated ACKs 指定的数据包。
- 如果再收到 duplicated ACKs,那么 cwnd = cwnd + 1。
- 如果收到了新的 ACK,那么 cwnd = sshthresh,然后就进入了拥塞避免的算法了。
如果你仔细思考一下上面的这个算法,你就会知道,上面这个算法也有问题,那就是它依赖于 3 个重复的 ACKs。注意,3 个重复的 ACKs 并不代表只丢了一个数据包,很有可能是丢了好多包。但这个算法只会重传一个,而剩下的那些包只能等到 RTO 超时。于是,进入了恶梦模式:超时一个窗口就减半一下。多个超时会超成 TCP 的传输速度呈级数下降,而且也不会触发 Fast Recovery 算法了。
1995 年,TCP New Reno(参见 RFC 6582 )算法提出来,主要就是在没有 SACK 的支持下改进 Fast Recovery 算法:
- 当 sender 这边收到了 3 个 Duplicated ACKs,进入 Fast Retransimit 模式,开发重传重复 ACKs 指示的那个包。如果只有这一个包丢了,那么,重传这个包后回来的 ACK 会把整个已经被 sender 传输出去的数据 ACK 回来。如果没有的话,说明有多个包丢了。我们叫这个 ACK 为 Partial ACK。
- 一旦 Sender 这边发现了 Partial ACK 出现,那么,sender 就可以推理出来有多个包被丢了,于是乎继续重传 sliding window 里未被 ack 的第一个包。直到再也收不到了 Partial ACK,才真正结束 Fast Recovery 这个过程。
这个 Fast Recovery 的变更是一个非常激进的玩法,他同时延长了 Fast Retransmit 和 Fast Recovery 的过程。