TCP
# TCP
TCP(Transmission Control Protocol:传输控制协议)
TCP 特点:
TCP 是面向连接的协议,也就是在通信之前会先建立连接
TCP 的一个连接有两端(点对点通信)
TCP 提供可靠的传输服务
TCP 协议提供全双工的通信
TCP 是面向字节流的协议
# TCP 三次握手四次挥手总结
序列号 seq:占 4 个字节,用来标记数据段的顺序,TCP 把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号 seq 就是这个报文段中的第一个字节的数据编号。
确认号 ack:占 4 个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1 即为确认号。
标志位:每个标志位占用 1Bit,共有 6 个,分别为 URG、ACK、PSH、RST、SYN、FIN
- URG:紧急指针(urgent pointer)有效。
- 确认 ACK:确认号是否有效,占 1 位,仅当 ACK=1 时,确认号字段才有效。ACK=0 时,确认号无效
- PSH:接收方应该尽快将这个报文交给应用层。
- RST:重置连接。
- 同步 SYN:连接建立时用于同步序号。当 SYN=1,ACK=0 时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得 SYN=1,ACK=1。因此,SYN=1 表示这是一个连接请求,或连接接受报文。SYN 这个标志位只有在 TCP 建产连接时才会被置 1,握手完成后 SYN 标志位被置 0。
- 终止 FIN:用来释放一个连接。FIN=1 表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接
PS:ACK、SYN 和 FIN 这些大写的单词表示标志位,其值要么是 1,要么是 0;ack、seq 小写的单词表示序号。
# 三次握手
建立 TCP 连接时,需要客户端和服务器共发送 3 个包。
第一次:客户端发送初始序号 seq=x 和 SYN=1 请求标志
第二次:服务器发送请求标志 SYN,发送确认标志 ACK,发送自己的序号 seq=y,发送客户端的确认序号 ack=x+1
第三次:客户端发送 ACK 确认号,发送自己的序号 seq=x+1,发送对方的确认号 ack=y+1
三次握手过程分析:
第一次:客户端向服务端发送 连接请求报文 ,首部的同步位 SYN=1,指明客户端的初始化序列号 seq=x,并进入 SYN_SENT 状态,等待服务器确认;服务器知道客户端发送,自己接收正常。SYN=1,seq=x
第二次:服务端收到请求报文,向 客户端发送 连接确认报文,在确认报文段中 SYN=1,ACK=1,确认号 ack=x+1,初始序号 seq=y。此时服务器进入 SYN_RECV 状态;客户端知道自己发送、接收正常,服务器接收、发送正常。ACK=1,ack=x+1,SYN=1,seq=y
第三次:客户端 收到 服务端的连接确认报文后,还要向 服务端 发出确认,确认报文段 ACK=1,确认号 ack=y+1,序号 seq=x+1(初始为 seq=x,第二个报文段所以要+1),此包发送完毕,客户端和服务器进入 ESTABLISHED(TCP 连接成功)状态,服务器知道客户端发送,接收正常,自己接收,发送也正常.seq=x+1,ACK=1,ack=y+1
# 问题 1:为什么不是两次握手:
两次握手没有办法保证交互双方同时具备发送与接收能力
# 问题 2:TCP 的三次握手一定能保证传输可靠吗?
不能
三次握手比两次更可靠,但也不是完全可靠,而追加更多次握手也不能使连接更可靠了。因此选择了三次握手。
世界上不存在完全可靠的通信协议。从通信时间成本空间成本以及可靠度来讲,选择了“三次握手”作为点对点通信的一般规则。
# 四次挥手
第一次挥手:客户端发出释放 FIN=1,自己序列号 seq=u,进入 FIN-WAIT-1 状态
第二次挥手:服务器收到客户端的后,发出 ACK=1 确认标志和客户端的确认号 ack=u+1,自己的序列号 seq=v,进入 CLOSE-WAIT 状态
第三次挥手:客户端收到服务器确认结果后,进入 FIN-WAIT-2 状态。此时服务器发送释放 FIN=1 信号,确认标志 ACK=1,确认序号 ack=u+1,自己序号 seq=w,服务器进入 LAST-ACK(最后确认态)
第四次挥手:客户端收到回复后,发送确认 ACK=1,ack=w+1,自己的 seq=u+1,客户端进入 TIME-WAIT(时间等待)。客户端经过 2 个最长报文段寿命后,客户端 CLOSE;服务器收到确认后,立刻进入 CLOSE 状态。
四次挥手过程分析:
- 第一次:客户端发出 连接释放报文段(FIN=1,序号 seq=u)并停止再发送数据,主动关闭 TCP 连接,进入 FIN_WAIT1(终止等待 1)状态,等待服务端的确认。
客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。
- 第二次:服务端收到连接释放报文段后即发出 确认报文段 (ACK=1,确认号 ack=u+1,序号 seq=v)表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态,此时的 TCP 处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入 FIN_WAIT2(终止等待 2)状态,等待服务端发出的连接释放报文段。
服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。
- 第三次:服务端没有要向客户端发出的数据,服务端发出 连接释放报文段 (FIN=1,ACK=1,序号 seq=w,确认号 ack=u+1)服务端进入 LAST_ACK(最后确认)状态,等待客户端的确认。
如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
- 第四次:客户端收到服务端的连接释放报文段后,对此发出 确认报文段 (ACK=1,seq=u+1,ack=w+1)客户端进入 TIME_WAIT(时间等待)状态。此时 TCP 未释放掉,需要经过时间等待计时器设置的时间 2MSL 后,客户端才进入 CLOSED 状态。
客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
四次挥手涉及两种报文:FIN 和 ACK。
FIN 就是 Finish 结束连接的意思,谁发出 FIN 报文,就表示它将不再发送任何数据,关闭这一方向的传输通道。
ACK 是 Acknowledge 确认的意思,它用来通知对方:你方的发送通道已经关闭。
问题 1. 为什么连接的时候是三次握手,关闭的时候却是四次握手?
因为当 Server 端收到 Client 端的 SYN 连接请求报文后,可以直接发送 SYN+ACK 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。但是关闭连接时,当 Server 端收到 FIN 报文时,很可能并不会立即关闭 SOCKET,所以只能先回复一个 ACK 报文,告诉 Client 端,"你发的 FIN 报文我收到了"。只有等到我 Server 端所有的报文都发送完了,我才能发送 FIN 报文,因此不能一起发送。故需要四步握手。
问题 2:如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP 还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为 2 小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔 75 秒钟发送一次。若一连发送 10 个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
问题 3:为什么 TIME_WAIT 状态需要经过 2MSL(最大报文段生存时间)才能返回到 CLOSE 状态?
MSL 是 Maximum Segment Lifetime 英文的缩写,中文可以译 报文最大生存时间
客户端需要保证最后一次发送的 ACK 报文到服务器,如果服务器未收到,可以请求客户端重发,这样客户端还有时间再发,重启 2MSL 计时。
虽然按道理,四个报文都发送完毕,我们可以直接进入 CLOSE 状态了,但是我们必须假象网络是不可靠的,有可能最后一个 ACK 丢失。所以 TIME_WAIT 状态就是用来重发可能丢失的 ACK 报文。在 Client 发送出最后的 ACK 回复,但该 ACK 可能丢失。Server 如果没有收到 ACK,将不断重复发送 FIN 片段。所以 Client 不能立即关闭,它必须确认 Server 接收到了该 ACK。Client 会在发送出 ACK 之后进入到 TIME_WAIT 状态。Client 会设置一个计时器,等待 2MSL 的时间。如果在该时间内再次收到 FIN,那么 Client 会重发 ACK 并再次等待 2MSL。所谓的 2MSL 是两倍的 MSL(Maximum Segment Lifetime)。MSL 指一个片段在网络中最大的存活时间,2MSL 就是一个发送和一个回复所需的最大时间。如果直到 2MSL,Client 都没有再次收到 FIN,那么 Client 推断 ACK 已经被成功接收,则结束 TCP 连接。
# 流量控制
流量控制(flow control):让发送方的发送速率不要太快,要让接收方来得及接收
利用滑动窗口实现流量控制
TCP 滑动窗口分为接受窗口,发送窗口 滑动窗口协议是传输层进行流控的一种措施,接收方通过通告发送方自己的窗口大小,从而控制发送方的发送速度,从而达到防止发送方发送速度过快而导致自己被淹没的目的。
# 拥塞控制
拥塞控制:防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
拥塞控制所要做的都有一个前提:网络能够承受现有的网络负荷。
拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素。
那么怎么知道当前网络是否出现了拥塞呢?
其实只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了用拥塞。
拥塞控制主要有四个算法:
慢启动
拥塞避免
让拥塞窗口缓慢增长,即每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加 1,而不是加倍。这样拥塞窗口按线性规律缓慢增长。
- 快重传
- 快恢复
# 重传机制
- 超时重传:发送数据时设定一个定时器,若在指定时间内没有收到应答报文,就会重发数据
发生超时重传的时机
(1) 数据包丢失
(2) 确认应答丢失
超时时间 RTO(Retransmission Timeout 超时重传时间) 选择
(1) 略大于 RTT(Round-Trip Time 往返时延)
(2) 重传超时策略:超时时间间隔加倍
- 快速重传
TCP 还有另外一种快速重传(Fast Retransmit)机制,它不以时间为驱动,而是以数据驱动重传。
发送方可以一次发送多个数据包,若中间的某个数据包丢失了,接收方会一直回复这个丢失的数据包应答报文,接收方若收到三次这个数据包的应答报文,就知道该报文还没有被接收方收到,可以重传这个数据包
存在问题:
因为接收方对后续的数据包也返回了丢失的那个应答报文,所以发送方不知道后续的数据包是否丢失,也就不知道应该重传丢失的数据包还是把后续的数据包都重传
- SACK
选择性重传,解决快速重传不知道重传哪些报文的缺点
实现方式:在 tcp 头部“选项”字段里加一个 SACK,将缓存的地图发送给发送方,这样发送方就知道哪些数据接收方收到了,哪些数据接收方没有收到,以便重传接收方没有收到的数据
- D-SACK
Duplicate SACK,对 SACK 的扩展,通过 SACK 告诉发送方哪些数据被重复接收了
实现方式:若有发送方有重复发送数据包,会通过 SACK 告诉发送方这这个数据包已被发送过
D-SACK 有这么几个好处:
(1)可以让「发送方」知道,是发出去的包丢了,还是接收方回应的 ACK 包丢了;
(2)可以知道是不是「发送方」的数据包被网络延迟了;
(3)可以知道网络中是不是把「发送方」的数据包给复制了;
# TCP 可靠传输
TCP 协议保证数据传输可靠性的方式主要有:
- 校验和
TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)。
- 确认应答+序列号(累计确认+seq)
接收方收到报文就会确认(累积确认:对所有按序接收的数据的确认)
TCP 给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
- 超时重传
当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
- 流量控制
TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。
接收方有即时窗口(滑动窗口),随 ACK 报文发送
- 拥塞控制
当网络拥塞时,减少数据的发送。
发送方有拥塞窗口,发送数据前比对接收方发过来的即使窗口,取小
慢启动、拥塞避免、拥塞发送、快速恢复
# TCP 和 UDP 的区别
相同点:
- 都是传输层协议
区别:
TCP 协议可靠;UDP 协议不可靠
TCP 协议是面向连接;UDP 协议采用无连接
TCP:用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)、UDP 用于传输少量数据(数据包模式)、速度快
TCP 协议负载较高,采用虚电路;UDP 采用无连接
# 名词解释
RTT 就是数据从网络一端传送到另一端所需的时间,也就是包的往返时间。
超时重传时间是以 RTO (Retransmission Timeout 超时重传时间)表示。