TCP传输控制协议相关知识整理

TCP、UDP区别

  • TCP是一个面向连接的(需要三次握手建立连接)、可靠的(有状态,可控的)、基于字节流(将IP包转成字节流)的传输层协议;
  • UDP是一个面向无连接的传输层协议;
  • UDP无状态,不可控的,基于数据报,而不是字节流;

TCP三次握手

  • 双方完成三次握手后,以证明双方均具备发送、接受能力;同步序列号,只有同步了序列号才有可靠传输,TCP 许多特性都依赖于序列号实现,比如流量控制、丢包重传等,这也是三次握手中的报文称为 SYN 的原因,SYN 的全称就叫 Synchronize Sequence Numbers(同步序列号)
    在这里插入图片描述

在这里插入图片描述

  1. 最开始双方都处于CLOSED状态,然后服务端启动服务,开始监听某个端口,进入了LISTEN状态;
  2. 客户端主动发起连接,发送一个标志位为:SYN的数据包,请求进行连接 , 自己变成了SYN-SENT状态;如果客户端长时间没有收到 SYN+ACK 报文,则会重发 SYN 包,重发的次数由 tcp_syn_retries 参数控制,默认是 5 次:
  3. 服务端接收到请求并且允许连接的话,就返回一个标志位为:SYN,ACK的数据包,表示可以通讯了,自己变成了SYN-REVD;当服务端收到 SYN 包后,服务端会立马回复 SYN+ACK 包,表明确认收到了客户端的序列号,同时也把自己的序列号发给对方。
  4. 客户端再发送发送一个标志位为:ACK的数据包给服务端,自己变成了ESTABLISHED状态;服务端收到ACK之后,也变成了ESTABLISHED状态,双方建立好连接;
  5. 在网络模型中的TCP层(第4层,非第3层的Flags)有个Flags字段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG(含有SYN或FIN标志位的包并不携带有效数据):
    1. SYN:表示请求建立连接;
    2. ACK:确认标志;
    3. RST:复位标志;
    4. URG:紧急标志;
    5. PSH:推标志,有DATA数据传输;
    6. FIN:结束标志,带有该标志置位的数据包用来结束一个TCP会话,但对应端口仍处于开放状态,准备接收后续数据。

TCP四次挥手

在这里插入图片描述

  1. 客户端向服务端说 我准备断开了:客户端要断开了,向服务端发送 FIN 报文,发送后客户端变成了FIN-WAIT-1状态,同时也变成了half-close(半关闭)状态,即无法向服务端发送报文,只能接收;
  2. 服务端跟客户端说 收到,服务端接收后向客户端确认,变成了CLOSED-WAIT状态,不是马上关闭连接,客户端接收到了服务端的确认,变成了FIN-WAIT2状态;
  3. 服务端内部花了点时间处理完这个客户端的报文,然后向客户端说 我可以断开了;,服务端向客户端发送FIN,自己进入LAST-ACK状态;
  4. 客户端说 收到,客户端收到服务端发来的FIN后,自己变成了TIME-WAIT状态,然后发送 ACK 给服务端;
  5. 服务端收到ACK报文,立即关闭连接,同时客户端需要等待足够异常反馈时长后才关闭连接,具体来说,客户端是等待 2 个 MSL(Maximum Segment Lifetime,报文最大生存时间), 在这段时间内如果客户端没有收到服务端的重发请求,那么表示 ACK 成功到达,挥手结束,否则客户端重发 ACK。

TCP连接状态详解

  • LISTEN: 侦听来自远方的TCP端口的连接请求
  • SYN-SENT: 再发送连接请求后等待匹配的连接请求
  • SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认
  • ESTABLISHED: 代表一个打开的连接
  • FIN-WAIT-1: 等待远程TCP连接中断请求,或先前的连接中断请求的确认
  • FIN-WAIT-2: 从远程TCP等待连接中断请求
  • CLOSE-WAIT: 等待从本地用户发来的连接中断请求
  • CLOSING: 等待远程TCP对连接中断的确认
  • LAST-ACK:等待原来的发向远程TCP的连接中断请求的确认
  • TIME-WAIT: 等待足够的时间以确保远程TCP接收到连接中断请求的确认
  • CLOSED:没有任何连接状态

TCP 报文头部的字段

TCP包头结构

在这里插入图片描述
TCP包的具体内容
在这里插入图片描述

  1. 源端口、目标端口
    如何唯一标识一个连接?答案是 TCP 连接的四元组——源 IP、源端口、目标 IP 和目标端口。
    那 TCP 报文怎么没有源 IP 和目标 IP 呢?这是因为在 IP 层就已经处理了 IP 。TCP 只需要记录两者的端口即可,mac地址记录在第2层的数据链路层(第2层),IP地址记录在网络层(第3层),端口记录在传输层(第4层)

  2. 序列号
    即Sequence number, 指的是本报文段第一个字节的序列号。
    从图中可以看出,序列号是一个长为 4 个字节,也就是 32 位的无符号整数,表示范围为 0 ~ 2^32 - 1。如果到达最大值了后就循环到0。
    序列号在 TCP 通信的过程中有两个作用:

    1. 在 SYN 报文中交换彼此的初始序列号。
    2. 保证数据包按正确的顺序组装。
  3. ISN
    即Initial Sequence Number(初始序列号),在三次握手的过程当中,双方会用过SYN报文来交换彼此的 ISN。
    ISN 并不是一个固定的值,而是每 4 ms 加一,溢出则回到 0,这个算法使得猜测 ISN 变得很困难。那为什么要这么做?
    如果 ISN 被攻击者预测到,要知道源 IP 和源端口号都是很容易伪造的,当攻击者猜测 ISN 之后,直接伪造一个 RST 后,就可以强制连接关闭的,这是非常危险的。
    而动态增长的 ISN 大大提高了猜测 ISN 的难度。

  4. 确认号
    即ACK(Acknowledgment number)。用来告知对方下一个期望接收的序列号,小于ACK的所有字节已经全部收到。

  5. 标记位
    前文已有说明,此处省略;

  6. 窗口大小
    占用两个字节,也就是 16 位,但实际上是不够用的。因此 TCP 引入了窗口缩放的选项,作为窗口缩放的比例因子,这个比例因子的范围在 0 ~ 14,比例因子可以将窗口的值扩大为原来的 2 ^ n 次方。

  7. 校验和
    占用两个字节,防止传输过程中数据包有损坏,如果遇到校验和有差错的报文,TCP 直接丢弃之,等待重传。

  8. 可选项
    可选项的格式如下:
    在这里插入图片描述
    常用的可选项有以下几个:

  • TimeStamp: TCP 时间戳,后面详细介绍。
  • MSS: 指的是 TCP 允许的从对方接收的最大报文段。
  • SACK: 选择确认选项。
  • Window Scale: 窗口缩放选项。

半连接队列和 SYN Flood 攻击的关系

  • 服务端在内部创建了两个队列:半连接队列和全连接队列,即SYN队列和ACCEPT队列;
  • 半连接队列
    当客户端发送SYN到服务端,服务端收到以后回复ACK和SYN,状态由LISTEN变为SYN_RCVD,此时这个连接就被推入了SYN队列,也就是半连接队列。
  • 全连接队列
    当客户端返回ACK, 服务端接收后,三次握手完成。这个时候连接等待被具体的应用取走,在被取走之前,它会被推入另外一个 TCP 维护的队列,也就是全连接队列(Accept Queue)。
  • SYN Flood 攻击原理
    SYN Flood 属于典型的 DoS/DDoS 攻击。其攻击的原理很简单,就是用客户端在短时间内伪造大量不存在的 IP 地址,并向服务端疯狂发送SYN。对于服务端而言,会产生两个危险的后果:
    1. 处理大量的SYN包并返回对应ACK, 势必有大量连接处于SYN_RCVD状态,从而占满整个半连接队列,无法处理正常的请求。
    2. 由于是不存在的 IP,服务端长时间收不到客户端的ACK,会导致服务端不断重发数据,直到耗尽服务端的资源。
  • 如何应对 SYN Flood 攻击?
    1. 增加 SYN 连接,也就是增加半连接队列的容量。
    2. 减少 SYN + ACK 重试次数,避免大量的超时重发。
    3. 利用 SYN Cookie 技术,在服务端接收到SYN后不立即分配连接资源,而是根据这个SYN计算出一个Cookie,连同第二次握手回复给客户端,在客户端回复ACK的时候带上这个Cookie值,服务端验证 Cookie 合法之后才分配连接资源。

TCP 快速打开TFO

  • 每次都三次握手好麻烦,这个优化后的 TCP 握手流程,也就是 TCP 快速打开(TCP Fast Open, 即TFO),优化的过程是这样的,还记得我们说 SYN Flood 攻击时提到的 SYN Cookie 吗?这个 Cookie 可不是浏览器的Cookie, 用它同样可以实现 TFO。
  • 首轮三次握手
    客户端发送SYN,服务端不是立即返回SYN,ACK,而是计算一个SYN Cookie,将这个Cookie放到 TCP 报文的 Fast Open选项中,然后才给客户端返回。
    客户端拿到这个 Cookie 的值缓存下来。后面正常完成三次握手。
    首轮三次握手就是这样的流程。而后面的三次握手就不一样啦!
  • 后面的三次握手
    在后面的三次握手中,客户端会将之前缓存的 Cookie、SYN 和HTTP请求(是的,你没看错)发送给服务端,服务端验证了 Cookie 的合法性,如果不合法直接丢弃;如果是合法的,那么就正常返回SYN + ACK。
    重点来了,现在服务端能向客户端发 HTTP 响应了!这是最显著的改变,三次握手还没建立,仅仅验证了 Cookie 的合法性,就可以返回 HTTP 响应了。
    当然,客户端的ACK还得正常传过来,不然怎么叫三次握手嘛。
    在这里插入图片描述
    注意: 客户端最后握手的 ACK 不一定要等到服务端的 HTTP 响应到达才发送,两个过程没有任何关系。
  • TFO 的优势
    TFO 的优势并不在与首轮三次握手,而在于后面的握手,在拿到客户端的 Cookie 并验证通过以后,可以直接返回 HTTP 响应,充分利用了1 个RTT(Round-Trip Time,往返时延)的时间提前进行数据传输,积累起来还是一个比较大的优势。

关于TCP报文还有很多内容,可以参考以下文章链接:

参考资料:(建议收藏)TCP协议灵魂之问,巩固你的网路底层基础
面试官:换人!换人!TCP 这几个参数都不懂,也来面试?

原文地址:https://www.cnblogs.com/zoulei0718/p/14315575.html