不落辰

知不可乎骤得,托遗响于悲风

0%

计算机网络-传输层-TCP

TCP概述
报文格式、发送方接收方状态机模型、流量控制、拥塞控制、三次握手四次挥手

TCP

  • 什么是TCP连接

    • 用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括Socket、序列号和窗口大小称为连接。
  • TCP 四元组可以唯一的确定一个连接,四元组包括如下:

    • 源地址
    • 源端口
    • 目的地址
    • 目的端口

概述

  • 点对点
    • 一个发送方,一个接收方
    • 多播对于TCP来说是不可能的。(一个发送方传送给多个接收方)
  • 可靠的、按顺序的字节流
    • 没有报文边界
  • 管道化(流水线)
    • TCP拥塞控制和流量控制设置窗口大小
  • 发送和接收缓存

    • MSS(MAX Segment Size):放入TCP报文段的最大应用层报文段大小。(应用层报文段的最大大小)
    • MTU(Maximum Transmission Unit) = IP Header + TCP Header + MSS(应用层报文段)

  • 全双工数据
    • 在同一连接中数据流双向流动
  • 面向连接
    • 三次握手:在数据交换之前,通过握手(交换控制报文) 初始化发送方、接收方的状态变量
    • TCP连接是一条逻辑连接,其共同状态仅保存在两个通信端系统的TCP程序中。
      • TCP连接的组成包括:一台主机上的缓存、变量和与进程连接的socket,另一台主机上的另一组缓存、变量和与进程连接的socket
    • 中间的网络元素如 路由器、交换机、中继器,没有为该连接分配任何缓存和变量。也即,不会维持TCP连接状态。
      • 中间路由器对TCP连接完全视而不见,它们看到的是数据报,而不是连接。
  • 有流量控制:
    • 发送方不会淹没接收方

报文结构

  • 源port、目的port:

    • 多路复用/分解来自或送到上层的数据
  • 检验和check sum

  • 序号sequence number (32bit) and 确认号acknowledgement number (32bit)

    • 用于实现可靠数据传输服务
  • 首部长度header length

    • TCP Header 长度
  • 标志

    • RSF位的组合代表了是第几次握手
  • 接收窗口receive window

    • 用于流量控制,指示接收方愿意接受的字节数量
  • 选项options

序号、确认号

  • 好图
  • 序号:
    • 报文段首字节的在字节流的编号
    • 一个报文段的序号 是该TCP报文段的数据部分的首字节的字节流编号
  • 确认号:
    • 期望从另一方收到的下一个字节的序号
    • 累计确认(与SR协议不同,SR协议是非累计确认)
    • ack number:已经收到了[begin,ack-1]的所有bytes,期待收到的下一个byte是ack 。 即期待收到的下一个TCP报文段的body的起始字节的序号是ack
  • TCP没有规定 接收方如何处理乱序的报文段
    • 丢弃
    • 缓存。(实际中使用的)
  • 对于一条TCP连接,双方随机选择初始序号
    • ?
  • telnet例子
    • 捎带:B到A的数据的ack确认被 捎带(装载) 在一个B到A的数据包文段中。
    • 顺带一句:初始序号随机 防止老连接的包造成影响。不过对方是如何知道自己的初始序号的?

往返延时(RTT)和 TCP超时

  • 怎样设置TCP超时?
    • 比RTT要长 
      • 但RTT是变化的
    • 太短:太早超时
      • 不必要的重传
    • 太长:对报文段丢失
      • 反应太慢,消极

往返时间RTT预估

  • 怎样估计RTT?
    • SampleRTT:测量从报文段发出到收到确认的时间
      • 如果有重传,忽略此次测量
    • SampleRTT会变化,因此估计的RTT应该比较平滑
      • 对几个最近的测量值求平均,而不是仅用当前的SampleRTT
  • EstimatedRTT = (1 - α) * EstimatedRTT + α * SampleRTT
    • 表示 当前最近一段时间的往返平均值
    • 指数加权移动平均:越近的样本权重越大

RTT变化 预估

  • DevRTT = (1-β) * DevRTT + β * |SampleRTT - EstimatedRTT|
    • 表示 当前采样值SampleRTT 离 估算平均值EstimatedRTT 的偏差程度 的一个平均值
    • 同样采用指数移动加权平均。

设置和管理 重传超时间隔

  • TimeoutInterval = EstimatedRTT + 4*DevRTT

TCP: 如何rdt?(可靠数据传输)

  • TCP在IP不可靠服务的基础上建立了rdt
    • pipeline的报文段
      • GBN + SR
    • 累计确认:像GBN
    • 单个定时器:发送方只设置一个定时器(GBN),且该定时器只和最老的段关联.像GBN
    • TCP没有规定 接收方如何处理乱序的报文段
    • 通过以下事件触发重传
      • 超时:当超时的时候 只**重放一个段(SR)**,且是最老的段。
      • 冗余ACK:触发快速重传机制
        • 例如收到ACK50之后,又收到3个ACK50

TCP发送方(简化)

  • 接下来考虑简化的TCP发送方
    • 忽略重复的确认
    • 忽略流量控制和拥塞控制

状态机

  • 发送窗口 : [base,next-1]

    • 发送窗口 size = next - base
    • next : 即将发送的报文段,也即紧挨着发送窗口的下一个报文段
    • next-1 : 最新的 已经发送 未确认的报文段
    • base : 最老的 已发送 未确认的报文段
    • base - 1 : 最新的被确认的分组
  • ack number:

    • 接收方接收到的顺序到来的最后一个字节 + 1(期待)。
    • 发送给发送方,ack告诉发送方[begin,ack-1]已经被确认。
    • 发送方的base移动到ack,因此接收到的ack是发送窗口的base

文字版 Action and Event

  • data received from application : 从应用层接收数据

    • 用nextseq创建报文段
    • 序号nextseq为报文段首字节的字节流编号
    • 如果还没有运行定时器,启动定时器
      • 定时器与最老未确认的报文段关联(即 定时器与base分组关联)
  • timeout : 定时器超时

    • 重传后沿最老的报文段(即 重传base
      • 只重传一个base分组(类似SR)
    • 重启timer
  • ACK received , with ACK field and value y收到确认

    • 如果收到的是对尚未确认的报文段的确认(接收到的ACK > 发送窗口的base)
      • 发送窗口的后沿向右侧移动,更新已被确认的报文序号。即 base 右移到ack的位置
      • base < next : 如果当前还有已经发送但没被确认的报文段,重启timer。
      • base = next : 如果当前没有已经发送但没被确认的报文段,无需启动timer。
  • 如下就要启动对报文段7的timer

code

  • 三件event 和 相应 action
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    NextSeqNum = InitialSeqNum
    SendBase = InitialSeqNum
    loop (forever) {
    switch(event)
    event: data received from application above
    create TCP segment with sequence number NextSeqNum
    if (timer currently not running)
    start timer pass segment to IP
    NextSeqNum = NextSeqNum + length(data)

    event: timer timeout
    retransmit not-yet-acknowledged segment with smallest sequence number
    start timer

    event: ACK received, with ACK field value of y
    if (y > SendBase) {
    SendBase = y
    if (there are currently not-yet-acknowledged segments)
    start timer
    }
    } /* end of loop forever */

例子

TCP接收方

  • RCF对于接收方返回ACK的建议。
    • (1)(2)

    • (3)

    • (4)

补充 : TCP发送方 之 快速重传机制

  • 超时周期往往太长:
    • 在重传丢失报文段之前的延时太长
  • 通过重复的ACK检测报文段丢失
    • 发送方通常连续发送大量报文段
    • 如果报文段丢失,通常会引起多个重复的ACK
  • 如果发送方收到同一数据的3个冗余ACK,重传最小序号的段:
    • 快速重传:在定时器过时之前重发报文段
    • 它假设跟在被确认的数据后面的数据丢失了
    • 第一个ACK是正常的;
    • 收到第二个该段的ACK,表示接收方收到一个该段后的乱序段;
    • 收到第3,4个该段的ack,表示接收方收到该段之后的2个,3个乱序段,可能性非常大段丢失了
  • 例子


  • 补充上文中的发送方简化版状态机

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    event: ACK received, with ACK field value of y 
    if (y > SendBase) {
    SendBase = y
    if (there are currently not-yet-acknowledged segments)
    start timer
    else
    stop timer
    }
    else {
    // ACK = sendBase
    increment count of dup ACKs received for y
    // ACK重传
    if (count of dup ACKs received for y = 3) {
    resend segment with sequence number y
    }
    }

流量控制

概念

  • 流量控制接收方控制发送方,不让发送方发送的太多、太快以至于让接收方的缓冲区溢出。
  • TCP接收方 通过填写TCP段头部的receiving window field来告知 TCP发送方 自己的空闲buffer大小
    • 进而控制TCP发送方的发送速度

流程

  • TCP接收方 通过填写TCP段头部的receiving window field来告知 TCP发送方 自己接收Buffer的空闲大小.

    • RcvBuffer大小通过socket选项设置 (典型默认大小为4096 字节)。
    • 很多操作系统自动调整RcvBuffer。
  • TCP发送方知道接收方的receiving window之后,通过限制未确认(“inflight”)字节的个数≤接收方发送过来的rwnd值,来保证接收方不被淹没。(意图控制发送方新发送的(新要送入接收方Buffer的)data size < free buffer space)

  • 接收buffer , recvWindow(free空间) 以及 , data to read by app

连接管理 (即 TCP三次握手 四次挥手)

  • 连接关闭的两军问题

TCP连接建立

  • TCP连接的建立会显著地增加人们感受到的时延。
  • 连接建立的本质
    • 知道要和对方通信
    • 双方准备通信资源 如 缓冲区
    • 控制变量置位 如连接初始序号 和初始化的recvBuffer大小

三次握手

  • 流程:client的进程向和server的进程建立TCP连接

  • 1. client向server发送SYN报文段

    • 请求发起连接,并告知对方自己的初始序列号。
    • 不含应用层数据
    • SYN = 1
    • seq = client_isn。
    • client状态变化:CLOSE -> SYN_SENT

  • 2. server向client发送SYNACK报文段(SYNACK segment)

    • 收到了client的连接请求,收到了对方的初始化序列号,并同意建立连接,并告知对方自己的初始序列号。
    • 不含应用层数据
    • SYN = 1
    • seq num = server_isn
    • ACK = 1 , ack num = client_isn + 1
    • server状态变化:LISTEN -> SYN_RCVD

  • 3. client向server发送发送ACK报文段

    • client告诉server,自己收到了对方对于连接建立的确认,以及收到了对方的初始化序列号。
    • 可含应用层数据
    • ACK = 1 , ack num = server_isn + 1
    • client状态:SYN_SENT -> ESTABLISHED
    • server收到client发送的这个ack报文段后:SYN_RCVD -> ESTABLISHED

三次握手问题

  • 三次而非两次?见blog TCP2

TCP连接关闭

四次挥手

  • 客户端,服务器分别关闭它自己这一侧的连接
    • 将TCP连接分为两个方向,每个方向单独拆除。
    • 发送FIN bit = 1的TCP段
  • 一旦接收到FIN,用ACK回应
    • 接到FIN段,ACK可以和它自己发出的FIN段一起发
  • 可以处理同时的FIN交换
  • 主动关闭连接的,才有 TIME_WAIT 状态

TIME_WAIT问题

连接管理状态机

  • client的状态机

  • server的状态机

拥塞控制

见blog 拥塞控制

没有准确定义

网络拥塞特点
延时大
为了让网络达到有效的泵出 我的输入要泵入很多速率
拥塞时会重传没有必要重传的分组 从而让网络更慢
不加控制 马上不可控制 网络瘫痪

拥塞控制目的:
不是为了不发生拥塞,而是在不发生拥塞的情况下,尽可能地提高它的发送速率。

TCP采用端到端控制
(互联网架构将复杂性放在端上)

流量窗口 拥塞窗口

警戒值之后线性增长
警戒值之前指数增长
喝的大醉 滑动窗口变为1 警戒值变为发疯的一半
半倒不倒 3个冗余ack
喝的半醉 滑动窗口减为一半,进入拥塞避免,省了一个慢启动阶段。

慢启动阶段并不慢。很快 指数型增加

慢启动 很快 时间忽略不计



tcp公平
udp对tcp不友好 只顾着自己


返回的ack 是 最老的 未确认的字节的编号

滑动窗口协议GO BY N ,SR 窗口如何滚动 接收窗口作用 这部分内容很重要 对理解pipeline协议 提高效率的同时实现可靠传递 很重要

快速重传:在定时器到时之前 如果收到3个冗余的ack 就重传

快速重传的各种情况

捎带发送确认

流量控制目的:发送方发送的不至于太快,