TCP 协议
TCP 协议
1 TCP 的报文结构
数据在使用 TCP 发送的时候,会分成一段一段发送,每一个数据段加上 TCP 头部,就是一个 TCP 报文。
OSI 七层协议中,第二层(数据链路层)的数据叫 Frame,第三层(网络层)的数据叫 Packet,第四层(传输层)的数据叫 Segment。
1.1 首部字段含义
源端口和目的端口
这里记录来源的应用程序端口号和访问目的应用程序的端口号。TCP 报文不负责 IP 地址相关,只负责端口相关。IP 数据包的中源 IP 地址,目的 IP 地址 和 TCP 报文中的源端口号和目的端口号一起唯一确定一条 TCP 连接。
序列号
序号是该报文发送的数据段的第一个字节的序号。
比如发送 100 kb 的数据。假如分四段,第一段包含 25 kb。则这一组数据的序号是从 0 到 25599,所以这段报文的序列号是 0。那第二段的 25 kb 就是 25600 到 51199,它的报文序列号就是 25600。
序列号确保了 TCP 传输的有序性。
序列号一共 32 位,可以表示的范围是 [0, 2^32],即最大4G(2^32 字节)。序列号到最大的时候,下一个序列号就又回到 0。
确认号
表示期望收到的对方下一个报文段的序号值。
TCP 要求每一个数据报文都需要确认收到。确认报文里就会带有确认号。确认号只有当 ACK 标志为 1 的时候才有效。
比如通讯的一方收到了第一个 25 kb 的报文,该报文的序号值为 0,那么就需要回复一个确认报文,这个确认报文中的确认号就是 25600。
首部长度(数据偏移)
4 位用来表示数据报文首部的长度。也就是报文数据段起始处距离报文起始处的距离。
数据偏移量这个字段以 32 bit (即 4 字节)为单位,4 位最大表示是 1111, 即十进制的 15。所以 TCP 首部最大长度为 15 * 4 = 60 字节。
如果 TCP 头部没有选项字段,则首部长度正好为 5。
保留位
6 位,保留以后使用,暂时都为 0。
标志位
标志位一共有 6 个,每个占 1 位。
紧急 URG(Urgent)
当 URG 为 1 时,表示紧急指针字段有效。告诉系统此报文中有紧急数据,应该尽快发送,而不要按照原来的排队顺序发送。
URG 需要与头部中的 紧急指针 字段配合使用。
确认ACK(Acknowlegemt)
当 ACK = 1 时,确认号有效,一般携带 ACK 标志的报文段称为 “确认报文段”
TCP 规定,在连接建立后所有传送的报文段都需要把 ACK 置为 1。
推送 PSH(Push)
当 PSH = 1 的时候,表示该报文段高优先级,接收方 TCP 应该尽快推送给接受应用程序。而不用等到整个 TCP 缓存都满了才交付。
复位 RST (Reset)
当 RST = 1 时,表示 TCP 连接中出现严重错误,需要释放并重新建立连接。
一般携带 RST 标志的报文段称为 “复位报文段”
同步 SYN (Synchronization)
当 SYN = 1 的报文段一般称为 “同步报文段”,表示是一个请求连接的报文段。
在 TCP 三次握手中的第一个报文就是同步报文。在建立连接的时候用来同步序号。
若对方同意建立连接,则在响应报文中使 SYN = 1 和 ACK = 1。
终止 FIN (Finis)
当 FIN = 1 的时候,表示发送方的数据已经发送完毕,请求断开连接。
一般携带 FIN 的报文段称为 “结束报文段”。
在 TCP 四次挥手的时候会用到结束报文段。
窗口大小
数据接收方告诉数据发送方自己的 TCP 接收缓冲区还能容纳的字节数。
这个可以控制发送端发送数据的频率,从而达到流量控制。因为 16 bit,所以最大可以达到 65535 字节。
如果要使用更大的窗口,需要使用选项中的窗口扩大因子选项。
校验和
发送端对 TCP 整体(头部部分和数据部分)内容计算校验和,接收端检验,以此验证数据是否损坏。
计算方法?伪报头?
紧急指针
当 URG = 1 时有效。紧急指针指明了紧急数据的长度。紧急数据放在数据部分的开头。紧急数据结束后才是普通数据。
所以序列号加上紧急指针值正好是紧急数据的最后一个字节的序号。
即使窗口为 0 也可以发送紧急数据。
选项
常见的字段是最长报文大小(Maximum Segment Size)。通常在建立连接(为建立连接发送的 SYN = 1 的报文)里设置。
指明本端所能接收的最大报文长度。
因为选项不一定正好 32 位。如果不够就需要加 0 填充。(因为首部长度字段的单位是 32 bit)
还有“窗口扩大因子”,“时间戳”等选项。
最长可达 40 字节。
数据部分
TCP 中的数据部分是可选的。在建立一个连接和连接终止时,双方交换的报文仅有首部。
如果一方没有数据发送,另一方确认也使用没有数据部分的纯首部来确认收到的数据。
处理超时的时候也会发送不带任何数据的报文段。
2 TCP 的连接
2.1 建立连接(三次握手)
第一次握手
客户端发送一个报文,SYN = 1,并初始化一个序列号 J。数据部分为空。
客户端[ -> SYN_SENT]
第二次握手
服务端收到客户端建立连接的请求后,回复一个确认报文,同时这也是一个建立连接报文,ACK = 1,SYN = 1,确认号 = J + 1。同时自己也初始化一个序列号 K。
这个报文也不携带数据。
服务端[LISEN -> SYN_RCVD]
第三次握手
客户端收到服务端的确认报文后需要再给服务端一个确认报文。
此时 SYN 不再为 1(我的理解是不需要告诉对方序列号了,同步序列号才使用 SYN)。ACK = 1,确认号 = K + 1,序列号 = J + 1。
服务端收到该报文时连接正式建立。
一般第三次握手会携带正常传输数据。
服务端[SYN_RCVD -> ESTABLISH]
客户端[SYN_SENT -> ESTABLISH ]
TCP Flood 攻击。
收到数据后不发送确认报文。
2.2 释放连接(四次挥手)
第一次挥手
一方 A 向另一方 B 发送 FIN = 1 的结束报文。序列号 = M。A 进入 FIN-WAIT-1
状态。
第二次挥手
B 向 A 发送 ACK = 1 的确认报文,确认号 = M + 1。 B 进入 CLOSE-WAIT
状态。
第三次挥手
A 收到 B发送的确认请求后,进入 FIN-WAIT-2
状态。
B 将所有数据发送完毕。然后 B 向 A 发送 FIN = 1 的结束报文。序列号 = N。然后进入 LAST-ACK
状态。
第四次挥手
A 收到 B 发送的连接释放报文后进入 TIME-WAIT
状态。
A 向 B 发送 ACK = 1 的确认报文。 序列号 = N + 1。 等待 2 MSL 后进去 CLOSE 状态,服务端在收到报文后进入 CLOSE
状态。
B 收到 A 发送的确认报文后进入 CLOSE
状态。
MSL(Maxinum Segment Lifetime) 叫做最长报文段寿命,根据 RFC 793 建议该值设置为 2 分钟。
3 TCP 可靠性交付的实现
由于网络层并不保证数据传输的可靠性,所以需要传输层自己保证,这也是 TCP 与其它协议不同的重要特性。
TCP 的可靠性主要包括:
-
能够处理传输过程中数据被破坏的问题。
-
能够处理数据重复接收的问题。
-
能够处理接收端数据乱序到达的问题。
-
能够发现数据丢失并解决。
由此引入了 TCP 针对可靠性实现的几个技术
-
校验和处理数据被破坏的问题。
-
数据分组编号处理重复接收,乱序到达的问题。
-
确认包和超时重传处理数据丢失的问题。
3.1 重传机制
TCP 可靠交付来源于每条发送的数据包都要对对方明确回应收到。
所以如果没有收到就要触发重传。
多久认为超时
RTO(Retransmission Time-Out) 重传超时时间
指发送端发送数据之后,等待多长时间如果没有收到该数据的 ACK 报文就就重传。
RTO 设置短了会导致网络阻塞。长了会导致效率低,性能差。
RTT(Round Trip Time) 连接往返时间
发送数据包开始到接收到它的 ACK 报文时的所花的时间。
超时重传
等到 RTO 时间到了触发重传。缺点都需要等待 RTO。
快速重传
策略:如果包没有连续到达就 ACK 最开始那个可能丢了的包,如果发送方连续三次收到相同的 ACK,就触发重传。
这样就不需要等待 RTO。
举例:发送端发送了 1,2,3,4,5五个包,接收到收到了 1,然后 ACK 回 2,如果接下来 3,4分别到了,但是两次都还是 ACK 回 2。这样发送端就知道 2 丢了,于是马上重传 2。另外,如果重传的 2 收到了,ACK 直接回 6。
快速重传可以不用等待 RTO,但是也有一个问题,如上面的例子,究竟是重传 2, 还是重传 2,3,4(比如发送了 20 份数据,收到了 3 个相同的 ACK,并不知道这 3 个 ACK 是因为收到那份消息发送的),仍然是一个艰难的选择。
SACK 方法
RTT 算法
所以 TCP 会通过测量来获取一个当前 RTT 的估计值,然后根据这个 RTT 值来设置 RTO。
这类算法叫做自适应重传算法。目前使用的是 Jacobson / Karels 算法。
3.2 滑动窗口
因为 TCP 需要保证可靠性所以需要了解网络处理数据的速度,避免阻塞,导致丢包。所以引入了滑动窗口来做流量控制。
参考
https://jerryc8080.gitbooks.io/understand-tcp-and-udp/chapter2.html
https://gyl-coder.top/ThreeHandshakesAndFourWaves/
http://hopehook.com/2018/04/17/internet_protocol_suite/
https://www.jianshu.com/p/ef69ebdf2990
https://jerryc8080.gitbooks.io/understand-tcp-and-udp/chapter5.html
https://www.jianshu.com/p/ef69ebdf2990