当前位置: 首页 > ai >正文

计算机网络(一)——TCP

1. TCP 的三个核心特性

TCP 是面向连接可靠传输基于字节流的协议。

  • 面向连接:通信双方必须先建立连接(虚拟的全双工信道),才能收发数据。
  • 可靠传输:通过序列号(Seq)、确认应答(ACK)、超时重传、流量控制和拥塞控制来保证数据不丢、不重、不乱序。
  • 基于字节流:TCP 把应用层数据当作一个连续的字节序列,分段封装成报文段传输,不关心消息边界。这意味着应用层要自己处理粘包/拆包问题(比如 Netty 的 LengthFieldBasedFrameDecoder )。

一个 TCP 连接在系统中由四元组唯一标识:

【源 IP, 源端口, 目的 IP, 目的端口】

内核会为每个连接维护一套状态信息,包括本端/对端序列号、发送/接收缓冲区、窗口大小等。

2. 三次握手

三次握手是 TCP 建立连接的过程:

  1. 第一次握手:客户端发送 SYN 报文(SYN=1,Seq=x),请求建立连接。
  2. 第二次握手:服务端收到 SYN,回复 SYN+ACK 报文(SYN=1,ACK=1,Ack=x+1,Seq=y),表示同意并同步序列号。
  3. 第三次握手:客户端收到 SYN+ACK,回复 ACK 报文(ACK=1,Ack=y+1,Seq=x+1),连接建立。
    在这里插入图片描述

为什么不是两次?
核心原因有三个:

  1. 防止历史连接干扰
    如果一个延迟很久的旧 SYN 报文到达服务端,服务端建立了连接,而客户端早已关闭,会导致“幽灵连接”。第三次握手能让客户端确认对端的响应是否是自己期望的。

  2. 确保双方序列号同步
    TCP 使用序列号来确认和重排数据包。三次握手可以保证双方初始序列号(ISN)都被确认,避免因序列号不同步导致数据错乱。

  3. 避免资源浪费
    如果没有第三步,服务端无法确认客户端是否收到 SYN+ACK。ACK 丢失时,服务端会一直等待,造成“半开连接”占满资源。

Linux 内核细节

  • ISN 生成方式:基于一个随时间递增的计数器 + 源/目的 IP + 端口等进行哈希,保证不可预测性(防止 TCP 序列号攻击)。
  • 重试策略:第一次握手丢失,客户端会按指数退避(1s、2s、4s…)重发 SYN,次数由 tcp_syn_retries 控制。
  • SYN 攻击防御:通过增大半连接队列(somaxconn)、开启 SYN Cookies(tcp_syncookies=1)、减少 SYN+ACK
    重传次数(tcp_synack_retries)等手段缓解。

3. 四次挥手:优雅断开连接

断开连接的四次挥手流程是这样的:

  1. 第一次挥手:主动关闭方(假设是客户端)发送 FIN 报文,表示没有数据要发了。
  2. 第二次挥手:服务端收到 FIN,返回 ACK,进入 CLOSE_WAIT 状态。这时服务端可能还有数据要发送。
  3. 第三次挥手:服务端发送 FIN 报文,表示自己也发完了。
  4. 第四次挥手:客户端返回 ACK,进入 TIME_WAIT 状态,等待 2MSL 后释放连接。

为什么需要四次?
因为 TCP 是全双工的,关闭连接需要双方分别关闭发送方向。FIN 只能单向关闭,所以需要两对 FIN+ACK。

TIME_WAIT 的意义

  • 确保最后的 ACK 能被对端收到(ACK 丢失时,对端会重发 FIN)。
  • 等待网络中可能残留的旧数据包消失,避免下一个连接收到脏数据。

Linux 内核细节

  • 默认 TIME_WAIT 持续 60s(tcp_fin_timeout 可调)。
  • 高并发短连接下,TIME_WAIT 会占用大量端口,可通过 tcp_tw_reuse(复用 TIME_WAIT 连接)和 tcp_tw_recycle(已废弃)优化。

4. 数据传输中的细节

TCP 在传输阶段依赖几个关键机制:

  1. 滑动窗口(Flow Control):接收方通过 Window Size 告诉发送方自己还能接收多少数据,防止溢出。
  2. 拥塞控制(Congestion Control):经典算法包括慢启动(Slow Start)、拥塞避免(Congestion Avoidance)、快速重传(Fast Retransmit)、快速恢复(Fast Recovery)。Linux 现在常用 CUBIC。
  3. 超时重传(RTO):根据 RTT(往返时延)动态计算。
  4. 延迟确认(Delayed ACK):减少 ACK 数量,但可能影响实时性。
  5. Nagle 算法:合并小包,减少包数量,但会增加延迟(Netty、游戏开发常关闭)。

5. 工程实践与常见坑

  • HTTP Keep-Alive:复用 TCP 连接,减少三次握手开销,但要注意服务器连接数限制。
  • 短连接高并发:TIME_WAIT 爆炸时,优化内核参数或使用连接池。
  • 半关闭连接:MySQL Binlog dump 是典型场景,客户端发送完请求,保持接收端开启。
  • 防御 SYN Flood:云厂商的负载均衡会在内核前就拦截,但自己写 TCP 服务要考虑 SYN Cookies。
http://www.xdnf.cn/news/17552.html

相关文章:

  • monorepo架构设计方案
  • LCR 120. 寻找文件副本
  • 【bug】diff-gaussian-rasterization Windows下编译 bug 解决
  • Redis 数据倾斜
  • 腾讯前端面试模拟详解
  • 从零构建自定义Spring Boot Starter:打造你的专属开箱即用组件
  • 【linux】企业高性能web服务器
  • Horse3D引擎研发笔记(四):在QtOpenGL下仿three.js,封装EBO绘制四边形
  • HarmonyOS 开发入门 第一章
  • AI驱动的智能编码革命:从Copilot到全流程开发自动化
  • LAMPLNMP 最佳实践
  • 基于FPGA的热电偶测温数据采集系统,替代NI的产品(二)总体设计方案
  • Python Day27 HTML 核心知识笔记及例题分析
  • 【Kafka系列】第三篇| 在哪些场景下会选择使用 Kafka?
  • 自建Web应用防火墙(WAF)
  • React 19 通用 ECharts 组件
  • uni-app app端安卓和ios如何申请麦克风权限,唤起提醒弹框
  • 什么是网络准入控制系统?解析一款网络准入的详细功能
  • FPGA+护理:跨学科发展的探索(二)
  • 最短路问题从入门到负权最短路
  • 【算法专题训练】11、字符串中的变位词
  • “鱼书”深度学习进阶笔记(3)第四章
  • MLAG双活网络妙招:BGP + 静态VRRP实现智能负载均衡
  • (一)vscode搭建espidf环境
  • Linux线程——线程控制及理解
  • LLM大语言模型初步学习认识
  • day23|前端学习三件套
  • 集成电路学习:什么是URDF Parser统一机器人描述格式解析器
  • 10种经典学习方法的指令化应用
  • 动态创建可变对象:Python类工厂函数深度解析