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

计算机网络(一)——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.dtcms.com/a/326198.html

相关文章:

  • JavaScript Const的基础使用
  • QML的中英文翻译
  • 快速搭建前端playwright工程
  • SpringAI实现Reread(Advisor)
  • DNS核心概念与BIND配置详解
  • C++11的历史和统一的初始化列表
  • Qt串口通信设计指南:通信层架构与实践
  • K8S学习----应用部署架构:传统、虚拟化与容器的演进与对比
  • 虚拟财产刑事辩护:跨地域性与匿名性带来的挑战
  • 记录一些sonic自动化运行中的问题
  • 常见通信协议详解:TCP、UDP、HTTP/HTTPS、WebSocket 与 GRPC
  • 基于 Axios 的 HTTP 请求封装文件解析
  • Rust:专业级错误处理工具 thiserror 详解
  • Nginx 从入门到实战:安装、配置、升级与高级应用全解析
  • Web 开发前端与后端 API 的交互
  • golang 基础案例_01
  • 【MYSQL】MySQL中On duplicate key update
  • 台式机内存条安装方法
  • Docker中安装MySQL 5的详细过程
  • 算法讲解--水果成篮
  • GitHub的简单使用方法----(2)
  • Android中Activity销毁底层原理
  • AVS Video Converter视频转换与编辑工具深度评测
  • 基于OpenCV的实时美颜技术:从传统算法到深度学习融合实现
  • 光功率dBm为何是负数?一文详解
  • Effective C++ 条款35:考虑 virtual函数以外的其他选择
  • Spring源码解析 - SpringApplication run流程-prepareContext源码分析
  • MD5:理解MD5 / MD5核心特性 / MD5 在前端开发中的常见用途 / 在线生成MD5 / js-md5
  • Linux Docker 运行SQL Server
  • loading效果实现原理