文章

网络协议打怪升级-传输层:TCP

网络协议打怪升级-传输层:TCP

1.TCP是什么

TCP是一种面向连接、可靠传输、基于字节流的传输层协议,与IP协议共同组成TCP/IP协议族的基础

2.TCP的核心概念

2.1.三次握手与四次挥手

此处应与UDP协议作为比较,TCP协议通过面向连接、顺序传输、流量控制等特性,保证该协议的数据传输的高可靠性。

  • 面向连接
    • TCP是基于连接进行数据传输的,开始数据传输之前,需要通过三次握手建立TCP连接;数据传输完成后,通过四次挥手结束TCP连接,释放资源
      • 握手与挥手时的标识位定义

      | 标识位 | 含义 | | — | — | | SYN | 发起建立连接请求,携带初始化序列号 | | ACK | 确认收到数据,携带确认号ACK=n,标识确认收到”n-1” | | SEQ | 标识数据段的序列号,用于顺序重组,保证顺序一致 | | FIN | 标识对方已经没有数据要发送了,请求关闭连接 |

      • 三次握手
        1
        2
        3
        
        1-客户端发送SYN=1,ACK=0,SEQ=x,请求建立连接,发送序号为x
        2-服务端收到请求,回复SYN=1,ACK=1,SEQ=y,ACK=x+1,服务端同一连接,发送初始序列号y,确认客户端的x
        3-客户端收到服务端的消息,回复ACK=1,SEQ=x+1,ACK=y+1,确认连接建立,发送确认号y+1
        

        为什么是三次握手?不是两次或四次?

        1
        2
        3
        4
        
        1-如果是两次握手,只能收到ACK=x+1和ACK=1,不能没有收到ACK=y+1,不能确认服务端的发送能力
        2-可靠性保证,如果只有两次握手,若服务端收到延迟到达的SYN时,会建立连接,然而此时是不需要建立连接的(连接已建立或已废弃),
        因此,需要第三次握手来保证服务端发送的SYN-ACK是针对当前连接的。
        3-三次握手已足以分别验证客户端与服务端的发送与接收能力,不需要再多一次握手造成资源浪费。
        
      • 四次挥手

      由于TCP是全双工协议(客户端和服务端都可以发送、接收数据),因此,需要四次挥手保证双方有序完成传输并释放资源。

      1
      2
      3
      4
      
      1-客户端发送FIN,表示传输已完成,并将自己的状态设置为FIN_WAIT_1
      2-服务端收到FIN,发送ACK给客户端确认收到的FIN,此时服务端状态为CLOSE_WAIT,客户端状态变为FIN_WAIT_2
      3-服务端继续发送剩余数据(如果有),然后向客户端发送FIN,表示自己的数据已传输完成,此时服务端状态变为LAST_ACK
      4-客户端收到FIN,发送ACK确认已收到服务端的结束信号。然后客户端与服务端都关闭连接
      

2.1.可靠传输

TCP传输是可靠的,可靠性的核心在于,即使网络出现丢包、乱序、重复或延迟,TCP也能确保数据按序无误交付,TCP通过以下机制保证其可靠性。

  • 1.序列号(SEQ):
    • 特性:TCP将数据视为字节流,每个字节会分配一个序列号,既检测丢包或重复包,也能支持乱序重组
    • 实现原理:
      • 三次握手中,双方交换初始序列号,随机生成xy
      • 传输过程中,每个数据端(Segment)携带段中第一个字节的序列号(Sequence Number)段中字节数(Length)
      • 接收方接收到消息后,会根据序列号重新排序并缓存,若缺少某段(如2000-2999),等待重传
    • 示例:
      • 发送方发送1:SEQ=1000,LEN=500;2:SEQ=1500,LEN=500
      • 如果接收方先收到2,接收方缓存,并等待1到达
    • 可靠性贡献:
      • 序列号确保数据按序交付,重复包被丢弃,缺失包被重发
  • 2.确认应答(ACK):
    • 特性:接收方(客户端与服务端)通过ACK(确认应答)通知发送方(已正确接收数据&&等待发送方发送的数据)序列,驱动后续过程
    • 示例:
      • 收到SEQ=1000,LEN=500,接收方回复ACK=1500,表示已收到1500之前,等待1500及之后
      • 若一段时间后客户端没有收到ACK=1500,重传数据包
      • 若服务端又收到数据包,丢弃并重新回复ACK=1500
    • 累计确认
      • 1-若前面还有包没收到,比如SEQ=500,LEN=500还未收到,则不回复ACK=1500
      • 2-回复ACK=1500表示已收到序列号为1500之前的所有数据
    • 捎带确认:
      • ACK通常随数据一起发送,减少开销
    • 可靠性贡献:
      • 确认应答让发送方直到哪些数据已送达,触发重传或继续发送
  • 3.重传机制:
    • 特性:处理数据丢失或错误(校验和失败),确保所有数据最终到达
    • 实现原理:
      • 超时重传:
        1
        2
        3
        
        1-发送方为每个段(Segment)设置超时时间RTO(Retransmission Timeout),基于往返时间RTT动态计算
        2-若超时未收到ACK,重发该段
        3-连续超时后,RTO翻倍,防止网络拥堵
        
      • 快速重传:
        1
        2
        3
        4
        5
        
        1-接收方接收到乱序段后,立即发送ACK
        2-发送方收到三个连续ACK后,立即认为ACK确认的段丢失
        举例:
        发送方发送SEQ=1000,1500,2000,2500;其中1000丢失,
        接收方收到1500后,发现1000没有收到,回复ACK=1000表示期望确认SEQ=1000的数据
        
      • 选择性确认:
        1
        2
        
        可选机制(RFC 2018),接收方报告已收到但非连续的段
        示例:收到1000-1499和2000-2499,SACK通知2000-2499,发送方只重传1500-1999
        
    • 可靠性贡献:
      • 重传确保丢失或错误的数据被重新发送,结合序列号和ACK实现数据段无遗漏
  • 4.滑动窗口:
    • 特性:
      • 允许多个数据段同时发送,而无需等待每个段的ACK,提高传输效率
      • 控制流量,避免接收方缓冲区溢出
    • 实现原理:
      • 窗口概念:
        1
        2
        3
        
        发送窗口:发送方可发送但未确认的字节范围
        接收窗口:接收方可接受的字节范围(基于接收方缓冲区大小)
        窗口大小由接收方在ACK中通过Window Size字段通知
        
      • 滑动机制:
        1
        2
        3
        4
        5
        6
        
        发送方发送窗口内的段,收到ACK后向前滑动窗口
        示例:
        1.初始:发送窗口1000-1999(大小1000)
        2.发送:SEQ=1000,LEN=500
        3.收到:ACK=1500,Window=1000
        4.窗口前滑,新窗口1500-2499
        
      • 零窗口处理:
        1
        2
        
        若接收方缓冲区满,回复window=0,发送方停止发送
        接收方回复后发送窗口更新(Window Update)
        
      • 流量控制:窗口大小动态调整,防止发送方过快压垮接收方
    • 可靠性贡献:
      • 滑动窗口通过批量发送和确认提高效率,同时也避免接收方过载而压垮接收方
  • 5.拥塞控制:
    • 特性:
      • 防止发送方过快发送数据导致数据拥堵(如路由器缓冲区溢出)
      • 在可靠性基础上优化网络性能
    • 实现原理:
      • TCP使用拥塞窗口(Congestion Window,cwnd)控制发送速率,与滑动窗口相组合,取两者最小值作为实际发送窗口,既优化网络性能也保证了可靠性
      • 慢启动:
        1
        2
        3
        4
        5
        6
        7
        
        初始cwnd较小(如1),每收到一个ACK,cwnd翻倍,直到达到慢启动阈值,或检测到拥堵
        示例:
        1-初始cwnd=1。
        2-收到一个ACK,cwnd=2。
        3-收到一个ACK,cwnd=4。
        ...
        n-达到慢启动阈值OR检测到拥堵,cwnd不再程指数级增长,转为每次+1的线性增长,若拥堵可能会降低cwnd
        
      • 拥塞避免: 超过慢启动阈值后,cwnd不再指数级增长,转为每次+1的线性增长,避免激进发送导致网络拥堵
      • 快速回复: 检测到丢包(三个重复ACK)后:cwnd = cwnd/2 + 3,并且进入拥塞避免,不再指数级上升cwnd
      • 超时重传: 若超时(未收到ACK),认为网络已经进入严重堵塞,此时慢启动阈值被设置为cwnd/2,并重新开始慢启动,即cwnd = 1
    • 可靠性贡献:
      • 拥塞控制动态调整发送频率,减少丢包,保证可靠性的基础上也优化了网络性能
  • 6.综合:可靠性的整体保障
    • 序列号+确认应答:按序发送,无重复、无丢失
    • 重传:弥补网络不可靠性
    • 滑动窗口+拥塞窗口:尽量保证网络效率的情况下提高数据传输的可靠性

2.2.TCP的传输方式

TCP是基于字节流的传输,将应用层的数据打包成报文段,并交给网络层(IP层)封装成包。TCP不关心数据边界,只保证字节的顺序和可靠性

  • 什么是基于字节流的传输? 所谓’字节流’是指应用层发送给TCP的数据被看作一串没有边界的字节序列,TCP不关心数据的消息边界,TCP只管把这些字节分段打包为字节段,并发送出去

  • 1.分段
    • 当应用层一次性传输的数据过大,大于一个窗口可传递的值,TCP会自动把它且分为多个TCP报文段,每个报文段包含段头段数据
    • 通常来说,TCP段头长度为20Byte,TCP段数据长度为1460Byte
  • 2.打包/合并包
    • 如果应用层发送的数据很小,TCP可能把多个应用层数据合并

2.3.错误校验

TCP使用一种叫做校验和的机制来检测数据在传输过程中是否发生损坏或丢失,实现简单,不校验错误,只发现错误

  • 校验范围
    • 【伪首部】+【TCP头部】+【TCP数据】
    • 【伪首部】指IP层的信息,如源IP、目标IP、协议号、TCP长度等,也就是说,校验和的计算不仅仅计算TCP层的数据,还计算了IP层的数据
  • 计算步骤
    • 把校验范围(【伪首部】+【TCP头部】+【TCP数据】)分为16位一组
    • 把16位的数值全部相加
    • 得到的结果再取反
    • 最终得到校验和
  • 当接收方接收到数据时,接收方对内容进行计算得到校验和,如果不等于报文中的校验和,说明数据损坏,TCP会丢弃报文段,并触发重传机制
  • 网络攻击者可以伪造TCP报文并计算校验和,TCP本身不能对抗此种恶意攻击,只能检测传输过程中的错误

3.TCP的使用场景

| 应用 | 描述 | | — | — | | HTTP/HTTPS | - | | SSH/Telnet | 远程命令行连接 | | FTP | 文件传输 | | SMTP | 邮件发送 | | 数据库连接 | 如MySQL、PostgreSQL等 |

4.总结

TCP是面向连接、可靠传输、基于字节流的协议。它通过三次握手建立连接,四次挥手断开连接。

由于序列号、应答确认、重传机制、滑动窗口、拥塞控制等机制的存在,既保证了TCP连接的高可靠性,也兼顾了网络性能

对于应用层传递下来的较大的包或较小的包,TCP有分段机制和打包机制,旨在提高传输效率,并保证包不丢失

校验和作为TCP报文的其中一个字段,用于保证报文传输过程中数据不出现错误,但校验和不能检验出恶意包,只能发现网络传输中的包错误,当发现错误时,通过重传机制通知发送方重新发送报文

本文由作者按照 CC BY 4.0 进行授权