💪
AndroidCollect
  • 写在前面
  • 计算机基础
    • 计算机组成原理
    • 算法
      • 查找
        • 二分查找
      • 排序
        • 简单排序
        • 高级排序
        • 特殊排序
      • 海量数据
      • 思想
        • 贪心
        • 分治
        • 动态规划
        • 回溯
      • 哈希算法
    • 数据结构
      • 队列
        • 知识点
        • 相关题目
          • 用两个栈实现队列
          • 实现循环队列
          • 用链表实现队列
          • 用数组实现队列
      • 栈
        • 相关算法题目
          • 用链表实现栈
          • 用数组实现栈
      • 链表
        • 知识点梳理
        • 相关算法题目
          • 删除倒数第n个结点
          • 合并两个有序链表
          • 检测单链表是否有环
          • 获取中间结点
          • 反转链表
      • 跳表
      • 哈希表
      • 树
        • 二叉树
        • 二叉查找树
        • AVL 树
        • Trie 树
        • 红黑树
      • 堆
        • 存储
        • 堆的应用
      • 图
    • 网络
      • 应用层协议
        • DNS
        • HTTP
        • HTTPS
      • 传输层协议
        • TCP
        • UDP
      • 输入网址后发生了什么
    • 操作系统
      • 内存
    • 数据库
  • 软件工程
    • 编程思想
    • 设计模式
      • 状态模式
      • 装饰器模式
      • 代理模式
      • 责任链模式
      • 建造者模式
      • 单例模式
      • 观察者模式
  • Java
    • 基础
    • 异常
    • 并发编程
      • ThreadLocal
      • 线程池
      • 理解 volatile
      • AbstractQueuedSynchronizer
    • 集合
      • LinkedHashMap 源码
      • HashMap 源码
    • 注解
    • 反射
      • JDK 动态代理
    • JVM
      • 自动内存管理机制
      • Class 文件格式
      • 类加载机制
      • Java 内存模型(JMM)
      • 字节码指令
      • HotSpot 虚拟机实现细节
    • 源码与原理
    • 各版本主要特性
  • Android
    • 基础组件
      • Context
      • Activity
        • 生命周期
        • 启动模式与任务栈
        • 启动流程
      • Service
      • ContentProvider
      • BroadcastReceiver
      • Fragment
      • View
        • 常用控件问题总结
          • RecyclerView
          • ViewPager2
        • CoordinatorLayout
        • SurfaceView
        • 事件分发
        • 绘制流程
        • 自定义 View
        • Window
    • 数据存储
      • 存储结构
      • Sqlite
      • 序列化
      • SharedPreferences
    • 资源
      • 图片加载
    • 动画
      • 属性动画
    • 线程和进程
      • Binder 机制
      • 跨进程通信
        • AIDL
    • 内部原理
      • 消息循环机制
      • Binder
      • Window
      • SparseArray
      • ArrayMap
      • RecyclerView
      • App 启动流程
    • 性能优化
      • 内存
        • 内存使用优化
        • 内存泄漏
      • 启动优化
      • 缩减包大小
      • 布局优化
      • ANR
    • 打包构建
      • dex 文件
      • APK 打包流程
      • APK 签名流程
    • 架构
      • 运行时
      • Android 系统架构
      • 应用项目架构
    • 开源框架源码或原理
      • RxJava
        • 使用笔记
        • 源码解析
      • Retrofit
      • ButterKnife
      • BlockCanary
      • LeakCanary
      • OkHttp
      • 图片加载
        • Glide
        • Picasso
    • 碎片化处理
      • 屏幕适配
    • 黑科技
      • 热修复
    • Jetpack
      • Lifecycle
      • Room
      • WorkManager
    • 新动态
      • AndroidX
      • 各系统版本特性
  • 开发工具
    • 正则表达式
    • ADB
    • Git
  • Kotlin
  • Flutter
  • 关于作者
  • 致谢
由 GitBook 提供支持
在本页
  • TCP
  • 报文结构
  • 建立连接(三次握手)
  • 断开连接(四次挥手)
  • 流量控制(Flow Control)
  • 机制
  • 小问题
  • 拥塞控制(Congestion Control)
  • 相关问题
  • TCP 和 UDP 的区别?
  • 为什么要三次握手?
  • 为什么要四次挥手?
  • 为什么四次挥手后客户端还要进入TIMED_WAIT?
  • 拥塞控制和流量控制都是什么,两者的区别?
  • 拥塞控制为什么对超时和三次冗余操作不同

这有帮助吗?

  1. 计算机基础
  2. 网络
  3. 传输层协议

TCP

Transmission Control Protocol

上一页传输层协议下一页UDP

最后更新于5年前

这有帮助吗?

TCP

面向连接、提供可靠的数据传输。

报文结构

建立连接(三次握手)

  • 客户端发送SYN报文段,SYN=1,seq=client_start_seq(其实序列号),进入 SYN_SENT 状态

  • 服务端接收报文段,发送SYN_ACK报文段,SYN=1,ACK=client_start_seq+1,seq=server_start_seq,进入 SYN_REVD 状态

  • 客户端接收SYN_ACK报文,发送一个报文段,SYN=0,ACK=sever_start_seq+1,可能会捎带数据,进入Established状态

  • 服务端收到报文后,进入Establish状态

断开连接(四次挥手)

  • 客户端发送FIN报文段,FIN=1,进入FIN_WAIT_1状态

  • 服务端发送ACK,进入 CLOSE_WAIT状态;客户端接收ACK 进入 FIN_WAIT_2 状态

  • 服务端发送FIN 报文段,进入 LAST_ACK 状态;客户端接收FIN报文段,并发送ACK,进入TIMED_WAIT ,一段时间后关闭连接

  • 服务端接收ACK后,关闭连接

流量控制(Flow Control)

使发送方发送速率不超过接收方接收速率。

通过让发送方维护一个接收窗口的变量,进行流量控制。

机制

假设 RcvBuffer 是接收方的接收缓存,应用缓存从接收缓存中读取数据;lastByteRead 是应用程序从缓存中读取最后一个字节的编号,lastByteRcvd 是放入接收缓存的最后一个接收到的字节编号。为了避免接收缓存溢出,必须保证:

lastByteRcvd-lastByteRead<=RcvBuffer

用 RcvWindow 表示接收窗口,则

RevWindow=RcvBuffer-[lastByteRcvd-lastByteRead]

即接收方最多还能接收 RcvWindow 个字节。

接收方将 RcvWindow 放入报文的接收窗口字段中,这样发送方就可以根据这个值来调整发送速率。发送方维护两个变量lastByteSent和lastByteAcked,而lastByteSent-lastByteAcked就是发送方已经发送但是未被接收方确认的数据量。通过保证:

lastByteSent-lastByteAcked<=RcvWindow

就能保证发送方的发送速率不超过接收方的接收速率。

小问题

当 RcvWindow=0,且接收方没有新的报文发送时,接收方无法得到RcvWindow的后续更新,此时即便接收方接收缓存已经可以继续接收数据,但它无法告诉发送方。因此TCP规定,当发送方接收到RcvWindow=0时,要继续发送只有一个字节数据的报文段,以此获取最新的 RcvWindow 值。

拥塞控制(Congestion Control)

控制流向整个整个网络中的数据量,避免拥塞引起丢包。

如何控制

遏制发送方,发送方维护拥塞窗口变量 CongWin,保证 :

lastByteSent-lastByteAcked<=min(CongWin,revWindow)

通过限制未被确认的数据量,间接的控制了发送方发送的数据量。

如何检测拥塞

出现超时或者收到接收方的三次冗余ACK(发生了丢包)

避免拥塞策略

  • 慢启动:CongWin 初始值为MSS,每过一个RTT(往返时延)CongWin翻倍,直到遇见丢包事或超时事件

  • 加性增,乘性减:发生丢包后CongWin减半,以后每收到一个ACk,增加一个MSS(最大报文段长,由链路层帧长度确定)

  • 对超时事件作出响应:超时后直接进入慢启动;三次冗余 CongWin 减半

相关问题

TCP 和 UDP 的区别?

TCP 提供可靠传输,面向连接;UDP 不可靠,不建立连接

为什么要三次握手?

如果一次或者两次握手就算有效,那么可以轻易制造SYN洪泛导致的DDOS攻击;另外如果没有最后一次挥手,在网络拥堵时,无法保证客户端在服务端发出ACK后还有效,容易导致资源浪费。 再多次的握手没有意义。

为什么要四次挥手?

关闭连接需要确保双方都没有数据要传输了。前两次挥手确保服务端知道了客户端关闭的意愿,但此时服务端可能还有数据要传输,所以需要再挥一次,但如果只挥一次,没法保证客户端知道了服务端关闭意愿,因此还需要客户端发一次ACK。

为什么四次挥手后客户端还要进入TIMED_WAIT?

如有必要则对 ACK 报文进行重传,避免报文段丢失。

拥塞控制和流量控制都是什么,两者的区别?

  • 流量控制是为了平衡发送方的发送速率和接收方的读取速率,防止接收方缓存溢出

  • 拥塞控制是为了避免整个网络链路过度拥堵,丢包率增加。

拥塞控制为什么对超时和三次冗余操作不同

三次冗余ACK代表虽然有丢包,但是网络状态还可以交付报文,而超时则意味着网络拥堵十分严重。

TCP 报文结构