# 运输层概述
计算机网络结构中的物理层、数据链路层和网络层共同解决了将主机通过异构网络互联起来所面临的问题,实现了主机到主机的通信
实际上计算机网络中进行通信的是真正实体是位于通信两端主机中的进程
如何为运行在不同主机上的应用进程提供直接的通信服务是运输层的任务,运输层协议又称为端到端协议
运输层直接为应用进程间的逻辑通信提供服务
运输层向高层用户屏蔽了下面网络核心的细节(如网络拓扑、所采用的路由选择协议等),它使应用进程看见的就好像是在两个运输层实体之间有一条端到端的逻辑通信信道
根据应用需求不同,因特网的运输层为应用层提供了两种不同的运输协议,即面向连接的 TCP 和无连接的 UDP
# 运输层端口号、复用与分用
运输层端口号
运行在计算机上的进程使用进程标识符 PID 来标志
因特网上的计算机并不是使用统一的操作系统,不同的操作系统又使用不同格式的进程标识符
为了使运行不同操作系统的计算机的应用进程之间能够进行网络通信,就必须使用统一的方法对 TCP/IP 体系的应用进程进行标识
TCP/IP 体系的运输层使用端口号来区分应用层的不同应用进程
- 端口号使用 16 比特表示,取值范围为 0~65535
- 熟知端口号:0~1023,IANA 把这些端口号指派给了 TCP/IP 体系中最重要的一些应用协议,例如:FTP 使用 21/20,HTTP 使用 80,DNS 使用 53
- 登记端口号:1024~49151,为没有熟知端口号的应用程序使用,使用这类端口号必须在 IANA 按照规定的手续登记,以防止重复
- 短暂端口号:49152~65535,留给用户进程选择暂时使用。当服务器进程收到用户进程的报文件,就知道了客户进程所用的动态端口号,通信结束后,这个端口号可供其他客户进程以后使用
- 端口号只具有本地意义,即端口号只是为了标识本计算机应用层中各进程,在因特网中,不同计算机的相同端口号是没有联系的
发送方的复用和接收方的分用
TCP/IP 体系的应用层常用协议所使用的运输层熟知端口号
UDP:
- RIP:520
- DNS:53
- TFTP:69
- SNMP:161
- DHCP:67/68
TCP:
- SMTP:25
- FTP:21/20
- BGP:179
- HTTP:80
- HTTPS:443
# UDP 和 TCP 对比
UDP 和 TCP 是 TCP/IP 体系结构运输层中两个重要协议
用户数据报协议 UDP
UDP 是无连接的
UDP 支持单播、多播以及广播(即支持一对一,一对多,多对一和多对多交互通信)
UDP 是面向应用报文的
UDP 向上层提供无连接不可靠传输服务(适用于 IP 电话、视频会议等实时应用)
UDP 用户数据报首部仅 8 字节
传输控制协议 TCP
- TCP 是面向连接的
- TCP 仅支持单播(即每一条 TCP 连接只能有两个端点 EP,只能是一对一通信)
- TCP 是面向字节流的
- TCP 向上层提供面向连接可靠传输服务(适用于要求可靠传输的应用,例如文件传输)
- TCP 用户数据报首部最小 20 字节,最大 60 字节
# TCP 的流量控制
一般来说,我们总是希望数据传输得更快一些
- 但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失
所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收
利用滑动窗口机制可以很方便地在 TCP 连接上实现对发送方的流量控制
- TCP 接收方利用自己的接收窗口的大小来限制发送窗口的大小
- TCP 发送方收到接收方的零窗口通知后,应启动持续计时器。持续计时器超时后,向接收方发送零窗口探测报文
习题
1、主机甲和主机乙之间建立了一个 TCP 连接,TCP 最大段长度为 1000 字节。若主机甲的当前拥塞窗口为 4000 字节,在主机甲向主机乙连续发送两个最大段后,成功收到主机乙发送的第一个段的确认段,确认段中通告的接收窗口大小为 2000 字节,则此时主机甲还可以向主机乙发送的最大字节数是(A)
A.1000 B.2000 C.3000 D.4000
解析:主机甲发送两个最大段后,收到第一个段的确认段,此时窗口大小仍为 4000,因此窗口前移一个段,删除第一个段的缓存,然后通告接收窗口大小为 2000 字节,因此,主机甲调整拥塞窗口为 2000 字节,此时发送的第二个段的确认还没有收到,因此,还可以向主机乙发送的最大字节数为 1000 字节,选 A
# TCP 的拥塞控制
若某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络性能就要变坏。这种情况就叫做拥塞
- 在计算机网络的链路容量(即带宽),交换节点的缓存和处理机等,都是网络的资源
若出现拥塞而不进行控制,整个网络的吞吐量将随输入负荷的增大而下降
假定有如下条件:
- 数据是单方向传送,而另一个方向只传送确认
- 接收方向总是有足够大的缓存空间,因而发送方发送窗口的大小由网络的拥塞程度来决定
- 以最大报文段 MSS 的个数为讨论问题的单位,而不是以字节为单位
发送方维护一个拥塞窗口 cwnd 的状态变量,其值取决于网络的拥塞程度,并且动态变化
- 拥塞窗口 cwnd 的维护原则:只要网络没有出现拥塞,拥塞窗口就再增大一些;但只要出现拥塞,拥塞窗口就减小一些
- 判断出现网络拥塞的依据:没有按时收到应当到达的确认报文(即发生超时重传)。
发送方将拥塞窗口作为发送窗口 swnd,即 swnd=cwnd
发送方维护一个慢开始 ssthresh 状态变量:
- 当 cwnd<ssthresh 时,使用慢开始算法
- 当 cwnd>ssthresh 时,停止使用慢开始算法而改用拥塞避免算法
- 当 cwnd=ssthresh 时,既可以使用慢开始算法也可以使用拥塞避免算法
慢开始
设置初始拥塞窗口值 cwnd 和慢开始门限值 ssthresh,每个传输轮次结束后,拥塞窗口值按指数增大,当拥塞窗口值到达慢开始门限值时,停止慢开始算法,启用拥塞避免算法。
慢开始是指在一开始向网络注入的报文段少,而不是拥塞窗口 cwnd 增长速度慢
拥塞避免
每个传输轮次结束后,拥塞窗口值只能线性加 1。
当重传计时器超时,判断网络很可能出现了拥塞,进行一下工作:
- 将 ssthresh 值更新为发生拥塞时 cwnd 值的一半
- 将 cwnd 值减少为 1,并重新开始慢开始算法
拥塞避免并非指完全能够避免拥塞,而是指在拥塞避免阶段将拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞
快重传
有时,个别报文段会在网络中丢失,但实际网络并未发生拥塞
- 这将导致发送方超时重传,并误认为网络发生了拥塞
- 发送方拥塞窗口 cwnd 又设置为最小值 1,并错误地启动慢开始算法,因而降低了传输效率
采用快重传算法可以让发送方尽早知道发生了个别报文段的丢失
所谓快重传,就是使发送方尽快进行重传,而不是等超时重传计时器超时再重传
- 要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认
- 即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认
- 发送方一旦收到了 3 个连续的重复确认,就将相应的报文段立即重传,而不是等该报文段的超时重传计时器超时再重传
- 对于个别丢失的报文段,发送方不会出现超时重传,也就不会误认为出现了拥塞(进而降低拥塞窗口 cwnd 为 1)。使用快重传可以使用整个网络的吞吐量提高越 20%
快恢复
发送方一旦收到 3 个重复确认,就知道现在只丢失了个别的报文段,于是不启动慢开始算法,而执行快恢复算法
- 发送方将慢开始门限 ssthresh 值和拥塞窗口 cwnd 值调整为当前窗口的一半;开始执行拥塞避免算法
- 也有的快恢复实现是把快恢复开始时的拥塞窗口 cwnd 值再增大一些,即等于新的 ssthresh+3
- 既然发送方收到 3 个重复的确认,就表明由 3 个数据报文段已经离开了网络
- 这 3 个报文段不再消耗网络资源而是停留子在接收方的接收缓存中
- 可见现在网络中不是堆积了报文段而是减少了 3 个报文段。因此可以适当把拥塞窗口扩大些
习题
1、一个 TCP 连接总是以 1KB 的最大段发送 TCP 段,发送方有足够多的数据要发送。当拥塞窗口为 16KB 时发生了超时,如果接下来 4 个 RTT(往返时间)内的 TCP 段的传输都是成功的,那么当第 4 个 RTT 的时间内发送的所有 TCP 段都得到了肯定应答时,拥塞窗口大小是(C)
A.7KB B.8KB C.9KB D.16KB
解析:当拥塞窗口为 16KB 时发生了超时,则拥塞窗口值改为 1,慢开始门限变为当前拥塞窗口值的一半,即 8KB,再过了 4 个往返时间后,拥塞窗口值变为了 8KB,此时由于所有 TCP 段都得到了肯定应答,因此采用拥塞避免算法,拥塞窗口线性增大 1,因此拥塞窗口大小为 9KB
# TCP 超时重传时间的选择
超时重传时间的选择是 TCP 最复杂的问题之一
- 超时重传时间 RTO 的值应略大于往返时间 RTT 的值
不能直接使用某次测量得到的 RTT 样本来计算超时重传时间 RTO
利用每次测量的 RTT 样本,计算加权平均往返时间 RTTs(又称为平滑的往返时间)
若 α 很接近于 0,则新的 RTT 样本对 RTTs 的影响不大
若 α 很接近于 1,则新的 RTT 样本对 RTTs 的影响较大
已成为建议标准的 RFC6298 推荐的 α 值为 0.125
用这种方法得出的加权平均往返时间 RTTs 就比测量出的 RTT 的值更加平滑
显然,超时重传时间 RTO 应略大于加权平均往返时间 RTTs
RFC6298 建议使用下式计算超时重传时间 RTO:
往返时间 RTT 的测量
源主机若误将确认当作是对原报文段的确认
- 所计算出的 RTTs 和 RTO 就会偏大,降低了传输效率
源主机若误将确认当作是对重传报文段的确认:
- 所计算出的 RTTs 和 RTO 就会偏小,导致报文段没必要的重传,增大网络符合
针对出现超时重传时无法测准往返时间 RTT 的问题,Karn 提出一个算法:
- 在计算加权平均往返时间 RTTs 时,只要报文段重传了,就不采用其往返时间 RTT 样本。也就是出现重传时,不重新计算 RTTs,进而超时重传时间 RTO 也不会重新计算
- 这又引起了新的问题。报文段的时延突然增大了很多,并且之后很长一段时间都会保持这种时延。因此在原来得出的重传时间内,不会收到确认报文段。于是就重传报文段。但根据 Karn 算法,不考虑重传的报文段的往返时间样本。这样,超时重传时间就无法更新。这会导致报文段反复被重传
- 因此,要对 Karn 算法进行修正。方法是:报文段每重传一次,就把超时重传时间 RTO 增大一些。典型的做法是将新 RTO 值取为旧 RTO 值的 2 倍
# TCP 可靠传输的实现
TCP 基于以字节为单位的滑动窗口来实现可靠传输
发送窗口后沿的移动情况有两种可能:
- 不动(没有收到新的确认)
- 前移(收到了新的确认)
发送窗口前沿的移动情况有三种可能:
- 通常是不断向前移动
- 不动
- 没有收到新的确认,对方通知的窗口大小也不变
- 收到了新的确认但对方通知的窗口缩小,使发送窗口前沿正好不动
- 后移(对方通知的窗口缩小了)(TCP 标准不建议这样做)
如何描述发送窗口的状态:
- 使用三个指针 P1,P2,P3 分别指向相应的字节序号
- 小于 P1 的是已发送并已收到确认的部分
- 大于等于 P3 的是不允许发送的部分
- P3-P1 = 发送窗口的尺寸
- P2-P1 = 已发送但尚未收到确认的字节数
- P3-P2 = 允许发送但当前尚未发送的字节数(又称为可用窗口或有效窗口)
虽然发送方的发送窗口是根据接收方的接收窗口设置的,但在同一时刻,发送方的发送窗口并不总是和接收方的接受窗口一样大
- 网络传送窗口值需要经历一定的时间滞后,并且这个时间还是不确定的
- 发送方还可能根据网络当时的拥塞情况适当减小自己的发送窗口尺寸
对于不按序到达的数据应如何处理,TCP 并无明确规定
- 如果接收方把不按序到达的数据一律丢弃,那么接收端口的管理将会比较简单,但这样做对网络资源的利用不利,因为发送方会重复传送较多的数据
- TCP 通常对不按序到达的数据是先临时存放在接收窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程
TCP 要求接收方必须有累积确认和捎带确认机制,这样可以减小传输开销。接收方可以在合适的事后发送确认,也可以在自己有数据要发送时把确认信息顺便捎带上。
- 接受方不应过分推迟发送确认,否则会导致发送方不必要的超时重传,这反而浪费了网络的资源。TCP 标准规定,确认推迟的时间不应超过 0.5 秒。若收到一连串具有最大长度的报文段,则必须要每隔一个报文段就发送一个确认 [RFC 1122]
- 捎带确认实际上并不经常发生,因为大多数应用程序很少同时在两个方向上发送数据
TCP 的通信是全双工通信。通信中每一方都在发送和接收报文段。因此,每一方都有自己的发送窗口和接受窗口。在谈到这些窗口时,一定要弄清楚是哪一方的窗口
习题
1、主机甲与主机乙之间已建立一个 TCP 连接,主机甲向主机乙发送了两个连续的 TCP 段,分别包含 300 字节和 500 字节的有效载荷,第一个段的序号为 200,主机乙正确接收到两个段后,发送给主机甲的确认序号是(D)
A.500 B.700 C.800 D.1000
解析:第一个段的序号为 200,第一个段包含 300 字节有效载荷,则第一个段最后一个字节的序号为 499,而两个 TCP 段是连续的,则第二个段的序号开头为 500,结尾为 999,因此主机乙收到之后,表明下一个需要的序号为 1000,将 1000 这个确认序号发送给主机甲,表明 1000 序号前的段正确接收,下一个期望接收的序号段是 1000
2、主机甲与主机乙之间已建立一个 TCP 连接,主机甲向主机乙发送了 3 个连续的 TCP 段,分别包含 300 字节,400 字节和 500 字节的有效载荷,第三个段的序号为 900,若主机乙仅正确接收了第 1 个段和第 3 个段,则主机乙发送给主机甲的确认序号是(B)
A.300 B.500 C.1200 D.1400
解析:主机乙仅正确接收第一个段和第三个段,因此需要发送第二个段的确认序号,表明第二个段缺失,需要重新传送,第三个段的序号为 900,第 2 个段包含 400 字节,因此,第二个段的序号为 500,因此选 B
# TCP 的运输连接管理
TCP 是面向连接的协议,它基于运输连接来传送 TCP 报文段
TCP 运输连接的建立和释放是每一次面向连接的通信中必不可少的过程
TCP 运输连接的建立有以下三个阶段:
- 建立 TCP 连接
- 数据传送
- 释放 TCP 连接
TCP 的运输连接管理就是使运输连接的建立和释放都能正常地进行
# TCP 的连接建立
TCP 的连接建立需要解决以下三个问题:
- 使 TCP 双方能够确知对方的存在
- 使 TCP 双方能够协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)
- 使 TCP 双方能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配
TCP 使用三报文握手建立连接
第三次握手是否多余:
- 不多余,为了防止已失效的连接请求报文段突然又传送到了 TCP 服务器,因而导致错误
习题
主机甲向主机乙发送一个(SYN=1,seq=11220)的 TCP 段,期望与主机乙建立 TCP 连接,若主机乙接受该连接请求,则主机乙向主机甲发送的正确的 TCP 段可能是(C)
A.(SYN=0,ACK=0,seq=11221,ack=11221) B.(SYN=1,ACK=1,seq=11220,ack=11220)
C.(SYN=1,ACK=1,seq=11221,ack=11221) D.(SYN=0,ACK=0,seq=11220,ack=11220)
解析:主机乙向主机甲发送的是针对 TCP 连接请求的确认报文,此时同步位 SYN 和确认位 ACK 都为 1,表明这是一个 TCP 连接请求确认报文,确认号字段 ack 的值是对主机甲中 TCP 客户进程所选择的初始序号 11220 的确认,因此 ack 字段为 11221,序号部分 seq 的值是主机乙中 TCP 服务器进程所选择的初始序号,可由 TCP 服务器进程随意指定,与其他报文的值无关
# TCP 的连接释放
TCP 通过四报文挥手来释放连接
最后等待的 2MSL 是为了保证 TCP 服务器进程可以收到最后一个 TCP 确认报文而进入关闭状态。
TCP 服务器进程每收到一次 TCP 客户进程的数据,就重新设置并启动保活计时器(2 小时定时)
若保活计时器定时周期内未收到 TCP 客户进程发来的数据,则当保活计时器到时候后,TCP 服务器进程就向 TCP 客户进程发送一个探测报文段,以后则每隔 75 秒钟发送一次,若一连发送 10 个探测报文段后仍无 TCP 客户进程的响应,TCP 服务器进程就认为 TCP 客户进程所在主机出了故障,接着就关闭了这个连接
# TCP 报文段的首部格式
为了实现可靠传输,TCP 采用了面向字节流的方式
但 TCP 在发送数据时,是从发送缓存取出一部分或全部字节并给其添加一个首部使之成为 TCP 报文段后进行发送
- 一个 TCP 报文段由首部和数据载荷两部分构成
- TCP 的全部功能都体现在它首部中各字段的作用
固定首部
源端口:占 16 比特,写入源端口号,用来标识发送该 TCP 报文段的应用进程
目的端口:占 16 比特,写入目的端口号,用来标识接收该 TCP 报文段的应用进程
序号:占 32 比特,取值范围为,序号增加到最后一个后,下一个序号就又回到 0
- 指出本 TCP 报文段数据载荷的第一个字节的序号
确认号:占 32 比特,取值范围为,序号增加到最后一个后,下一个序号就又回到 0
- 指出期望收到对方下一个 TCP 报文段的数据载荷的第一个字节的序号,同时也是对之前收到的所有数据的确认
- 若确认号 = n,则表明到序号 n-1 为止的所有数据都已正确接收,期望接收序号为 n 的数据
确认标志位 ACK:取值为 1 时确认号字段才有效;取值为 0 时确认号字段无效
- TCP 规定,在连接建立后所有传送的 TCP 报文段都必须把 ACK 置 1
数据偏移:占 4 比特,并以 4 字节为单位
- 用来指出 TCP 报文段的数据载荷部分的起始处距离 TCP 报文段的起始处有多远
- 这个字段实际上是指出了 TCP 报文段的首部长度
- 首部固定长度为 20 字节,因此数据偏移字段的最小值为 (0101)
- 首部最大长度为 60 字节,因此数据偏移字段的最大值为 (1111)
保留:占 6 比特,保留为今后使用,但目前应置为 0
窗口:占 16 比特,以字节为单位,指出发送本报文段的一方的接收窗口
- 窗口值作为接收方让发送方设置其发送窗口的依据
- 这是以接收方的接受能力来控制发送方的发送能力,称为流量控制
校验和:占 16 比特,检查范围包括 TCP 报文段的首部和数据载荷两部分
- 在计算校验和时,要在 TCP 报文段的前面加上 12 字节的伪首部
同步标志位 SYN:在 TCP 连接建立时用来同步序号。
终止标志位 FIN:用来释放 TCP 连接
复位标志位 RST:用来复位 TCP 连接
- 当 RST=1 时,表明 TCP 连接出现了异常,必须释放连接,然后再重新建立连接
- RST 置 1 还用来拒绝一个非法的报文段或拒绝打开一个 TCP 连接
推送标志位 PSH:接收方收到该标志位为 1 的报文段会尽快上交应用进程,而不必等到接收缓存都填满后再向上交付
紧急标志位 URG:取值为 1 时紧急指针字段有效;取值为 0 时紧急指针字段无效
紧急指针:占 16 比特,以字节为单位,用来指明紧急数据的长度
- 当发送方有紧急数据时,可将紧急数据插队到发送缓存的最前面,并立刻封装到一个 TCP 报文段中进行发送。紧急指针会指出本报文段数据载荷部分包含了多长的紧急数据,紧急数据之后是普通数据
扩展首部:
- 最大报文段长度 MSS 选项:TCP 报文段数据载荷部分的最大长度
- 窗口扩大选项:为了扩大窗口(提高吞吐率)
- 时间戳选项:
- 用来计算往返时间 RTT
- 用来处理序号超范围的情况,又称为防止序号绕回 PAWS
- 选择确认选项:用来实现选择确认功能
- 填充:由于选项的长度可变,因此使用填充来确保报文段首部能被 4 整除(因为数据偏移字段,也就是首部长度字段,是以 4 字节为单位的)