传输层
传输层也称为运输层(Transport Layer)。在此层的分组,TCP称为“报文段”,UDP称为“数据报“。
进程到进程的数据交付(多路复用与多路分解)和差错检查是两种最低限度的传输层服务,也是UDP所能提供的仅有的两种服务。
端口号
端口号为一个16比特的值,即范围为 0-65535。其中 0-1023 称为“周知端口号”。
UDP套接字由一个二元组全面标识:目的IP地址、目的端口号。
TCP套接字由一个四元组全面标识:源IP地址、源端口号、目的IP地址、目的端口号。
TCP与UDP的比较
相比TCP,UDP满足:
- 关于发送什么数据以及何时发送的应用层控制更精细
- 无需连接建立
- 无连接状态(无须保存与维护连接状态,节约资源)
- 分组的首部开销小。(TCP:20 Bytes,UDP:8 Bytes)
UDP
报文段格式
- 源端口号 (2 bytes)
- 目的端口号 (2 bytes)
- 长度 (2 bytes)
- 检验和 (2 bytes)
- 应用数据
当一台主机接收一个UDP分组,它的目的端口与运行中的任一UDP套接字都不匹配,则该主机发送一个特殊的ICMP数据报。
可靠数据传输
解决流水线的差错恢复有2种基本方法:
- 回退N步(Go-Back N,GBN),即“滑动窗口协议”(Sliding-Window Protocol)
- 选择重传(Selective Repeat,SR)。选择重传协议通过让发送方仅重传那些它怀疑在接收方出错(即丢失/受损)的分组而避免了不必要的重传。这种个别的、按需的重传要求接收方逐个确认正确接收的分组。对于选择重传协议,其窗口长度必须小于等于序号空间的一半。
TCP
概念
- 发起连接的称为客户,另一方称为服务器。
- TCP可从缓存中取出并放入报文段中的数据数量受限于最大报文段长度MSS(Maximum Segment Size)。MSS通常根据最初确定的由本地发送主机发送的最大链路层帧长度(最大传输单元MTU,Maximum Transmission Unit)。该MSS要保证一个TCP报文段(当封装在一个IP数据报中)加上TCP/IP首部长度(通常为40字节 [TCP首部20字节,IP首部20字节])须能放入单个链路层帧中。以太网和PPP链路层协议都具有1500字节的MTU,因此MSS的典型值为1460字节。注意MSS是指在报文段里应用层数据的最大长度而非指包括首部的TCP报文段的最大长度。
TCP报文段首部
源端口号 (16 bits)
目的端口号 (16 bits)
序号 (32 bits)
确认号 (32 bits)
首部长度 (4 bits)
- 以 32 bits (4 bytes) 的字为单位的TCP首部长度
- 典型长度为20字节,即值为5 (20 bytes = 5 * 4 bytes)
- 最大范围:$2^4 \times 32 \ bits=16 \times 4 \ bytes=64 \ bytes$
保留未用 (4 bits)
CWR (1 bit)
ECE (1 bit)
URG (1 bit):指示报文段里存在着被发送端的上层实体置为紧急的数据
ACK (1 bit)
PSH (1 bit):指示接收方应立即将数据交给上层
RST (1 bit)
SYN (1 bit)
FIN (1 bit)
接收窗口 (16 bits):用于流量控制,指示接收方愿意接受的字节数量
因特网检验和 (16 bits)
紧急数据指针 (16 bits):指出紧急数据的最后一个字节;当紧急数据存在并给出指向紧急数据尾指针时,TCP必须通知接收端的上层实体
选项 (可选且变长)
序号SYN与确认号ACK
主机A填充进报文段的确认号是主机A期望从主机B收到的下一字节的序号
TCP只确认该流中至第一个丢失字节为止的字节,所以TCP被称为提供累计确认(cumulative acknowledgment)
一条TCP连接的双方均可随机地选择初始序号,这样做可以减少将那些仍在网络中存在的,来自两台主机之间先前已终止的连接的报文段误认为是后来这两台主机之间新建的连接所产生的有效报文段的可能性(且该新连接碰巧与旧连接使用了相同的端口号)
该客户到服务器的数据的确认被装载在一个承载服务器到客户的数据的报文段中,这种确认被称为是捎带(piggybacked)在服务器到客户的报文段中的。
估计往返时间(定时器时长的设定)
报文段的样本RTT(表示为 $SampleRTT$)就是从某报文段被发出(即交给IP)到对该报文段的确认被收到之间的时间量。
大部分TCP的实现仅能某个时刻做一次 $SampleRTT$ 测量,而不是为每个发送的报文段估计 $SampleRTT$,从而产生一个接近每个RTT的新 $SampleRTT$ 值。
另外,TCP绝不为已被重传的报文段计算 $SampleRTT$。
显然随各种环境变化,报文段的 $SampleRTT$ 会波动,由于这种波动的存在,任何指定的 $SampleRTT$ 值可能都不是特定的。于是为估计一个相对典型的RTT,要采取某种对 $SampleRTT$ 取平均的方法,TCP维持一个 $SampleRTT$ 均值(称为 $EstimatedRTT$)。一旦获得一个新的 $SampleRTT$ 时,TCP就会根据以下公式求得(更新)$EstimatedRTT$:
$$EstimatedRTT=(1-\alpha) \cdot EstimatedRTT + \alpha \cdot SampleRTT$$
在 RFC 6298 中给出的 $\alpha$ 推荐值为 $\alpha = 0.125$,从统计学观点讲,这种平均被称为“指数加权移动平均”(Exponential Weighted Moving Average,EWMA)。这种加权平均对最近的样本赋予的权值要大于对旧样本赋予的权值。
除估算RTT外,测量RTT的变化也是有价值的。RFC 6298 中也定义了RTT偏差 $DevRTT$,用于估算 $SampleRTT$ 一般会偏离 $EstimatedRTT$ 的程度:
$$DevRTT = (1-\beta) \cdot DevRTT + \beta \cdot\lvert SampleRTT-EstimatedRTT \rvert$$
$DevRTT$ 是一个 $SampleRTT$ 与 $EstimatedRTT$ 之间差值的 EWMA,其中 $\beta$ 的推荐值为 $\beta = 0.25$。
设置和管理重传超时间隔
将超时间隔设为 $EstimatedRTT$ 加上一个余量,当 $SampleRTT$ 值波动较大时,这个余量应该大些;反之应小些。$DevRTT$ 在此发挥作用:
$$TimeoutInterval = EstimatedRTT + 4 \cdot DevRTT$$
事实上大多数TCP实现,只是在每次重传时将 $TimeoutInterval$ 变为2倍。
推荐的初始 $TimeoutInterval$ 的值为1秒,在出现超时该值将加倍,以免即将被确认的后继报文段过早超时,然而只要收到报文段并更新 $EstimatedRTT$,就使用上式更新 $TimeoutInterval$ [每当定时器在另两个事件(收到上层应用的数据/收到ACK)中的任意一个启动时,$TimeoutInterval$ 由最近的 $EstimatedRTT$ 与 $DevRTT$ 值推算得到]。
有些版本的TCP还有一个隐式NAK机制,在TCP的快速重传机制下,收到对一个特定报文段的3个冗余ACK就可作为对后面报文段的一个隐式NAK,从而在超时之前触发对该报文段的重传。
快速重传 Fast Retransmit
- 冗余ACK(Duplicate ACK):再次确认某个报文段的ACK,而发送方先前已经收到对该报文段的确认;
- 因为TCP不使用否定确认,所以接收方不能向发送方发回一个显式的否定确认。相反,它只是对已经接收到的最后一个按序字节数据进行重复确认;
- 因为发送方经常一个接一个地发送大量的报文段,若一个报文段的丢失,就很可能引起许多一个接一个的冗余ACK。若TCP发送方接收到对相同数据的3个冗余ACK,它把这当作一种指示,说明跟在这个已被确认过3次的报文段之后的报文段已丢失。一旦收到3个冗余ACK,TCP就执行快速重传。
产生TCP ACK的建议 (RFC 5681)
事件 | TCP接收方动作 |
---|---|
具有所期望序号的按序报文段到达,所有在期望序号及以前的数据都已被确认 | 延迟的ACK。对另一个按序报文段的到达最多等待 500ms,若一个按序报文段在此时间间隔内未到达,则发送一个ACK。 |
具有所期望序号的按序报文段到达,另一个按序报文段等待ACK传输 | 立即发送单个累积ACK,以确认两个按序报文段 |
比期望序号大的失序报文段到达,检测出间隔 | 立即发送冗余ACK,指示下一个期待字节的序号(即间隔的低端序号) |
能部分或完全填充接收数据间隔的报文段到达 | 倘若该报文段起始于间隔的低端,则立即发送ACK |
流量控制 Flow-Control Service
消除发送方使接收方缓存溢出的可能性
速度匹配服务,即发送方的发送速率与接收方的接受速率匹配
接收窗口大小 $rwnd=RcvBuffer - (LastByteRcvd - LastByteRead)$
则发送方在该连接的整个生命周期须保证 $LastByteSent - LastByteAcked \le rwnd$
当接收方的窗口满时使 $rwnd=0$,按上述方案可能导致发送方一直等待接收方。为此TCP规定要求:当接收方的接收窗口为 $0$ 时发送方继续发送只有一个字节数据的报文段,这些报文段会被接收方确认,最终缓存将开始清空,且确认报文里将包含一个非 $0$ 的 $rwnd$ 值。
TCP三次握手
RST
当一台主机收到一个TCP报文段,但其端口号或源IP地址与该主机上进行中的套接字都不匹配时,该主机将向源发送一个特殊重置报文段,即RST标志位置1。当主机发送一个重置报文段时,它告诉该源”我没有那个报文段的套接字,请不要再发送该报文段了“。
拥塞控制
概括
运行在发送方的TCP拥塞控制机制跟踪一个额外的变量,“拥塞窗口” $cwnd$ (congestion window):
$$LastByteSent-LastByteAcked \le min(rwnd, cwnd)$$
“丢包事件”定义为:出现超时或收到来自接收方的3个冗余ACK(即4个确认,一个初始ACK和其后的3个冗余ACK)。
一个丢失的报文段表示拥塞出现,因此当丢失报文段时应当降低TCP发送方的速率。
一个确认报文段指示该网络正在向接收方交付发送方的报文段,因此当对先前未确认报文段的确认到达时,能够增加发送方的速率。(确认的到达被认为是“一切顺利”的隐含指示)
具体算法
《计算机网络:自顶向下方法》P179 图3-51
公平性
公平性与UDP
从TCP的视角来看,UDP不与其它连接合作,也不适时地调整其传输速率,因为TCP拥塞控制在面临拥塞增加(丢包)时,将降低其传输速率,而UDP源则不必这样做,如此UDP源有可能压制TCP流量。
公平性与并行TCP连接
例如Web服务器通常使用多个并行TCP连接来传送一个Web页中的多个对象。当一个应用使用多条并行连接时,它占用了一条拥塞链路中较大比例的带宽。
明确拥塞通告:网络辅助拥塞控制
一个TCP发送方不会收到来自网络层的明确拥塞指示,而是通过观察分组丢失来推断拥塞,然而对于IP和TCP的扩展方案RFC 3168已经提出并已经实现和部署,该方案允许网络明确向TCP发送方和接收方发出拥塞信号,这种形式的网络辅助拥塞控制称为明确拥塞通告(Explicit Congestion Notification,ECN)。
在网络层,IP数据包首部的服务类型字段中的两个比特被用于ECN。路由器所使用的一种ECN比特设置指示该路由器正在历经拥塞。该拥塞指示则由被标记的IP数据报所携带,送给目的主机,再由目的主机通知发送主机。
RFC 3168推荐仅当拥塞持续不断存在时才设置ECN比特。(发送主机所使用的另一种ECN比特设置通知路由器发送方和接收方是ECN使能的,因此能够对于ECN指示的网络拥塞采取行动)
当接收主机中的TCP通过一个接收到的数据报收到了一个ECN拥塞指示时,接收主机中的TCP通过在接收方到发送方的TCP ACK报文段中设置ECE(明确拥塞通告回显,ECN Echo)比特,通知发送主机中的TCP收到拥塞指示。接下来,TCP发送方通过减半拥塞窗口对一个具有ECE拥塞指示的ACK作出回应,就像它对丢失报文段使用快速重传作出回应一样,并且在下一个传输的TCP发送方到接收方的报文段首部中对CWR(拥塞窗口缩减)比特进行设置。
Reference
James F. Kurose and Keith W. Ross, Computer Networking: A Top-Down Approach, 7E, Pearson Education, 2017. 中译版:陈鸣译,2019年,机械工艺出版社。