Skip to content

传输层

约 4635 个字 预计阅读时间 23 分钟

传输层服务

数据链路层提供链路上相邻节点之间的逻辑通信,网络层提供主机之间的逻辑通信。

而传输层为运行在不同主机上的进程之间提供逻辑通信,属于面向通信部分最高层,同时也是用户功能中的最低层。

cn_topic4_1.png

对于网络层来说,通信双方通过主机的 IP 来辨识;对于传输层来说,通信真正的端点不是主机,而是主机中的进程,通过应用进程的套接字 Socket来辨识:

\[ \text{Socket}=(\text{IP 地址 : 端口号}) \]

套接字唯一标识了网络中一台主机上的一个应用进程,它由主机的 IP 地址以及应用程序的端口号拼接而成。

在同一台计算上,TCP 和 UDP 协议可以使用相同的端口号

端口号长 16-bit,最多可表示 \(2^{16}=65536\) 个不同端口号。根据端口号范围,我们划分两类:

  • 1) 服务器端使用的端口号: 其中 0-1023 被指派给 TCP/IP 体系中最重要的一些应用程序,称为熟知端口号;1024-49151 提供给其它应用程序使用,并且需要在 IANA 登录防止重复
    • 例如 22:FTP, 23:TELNET, 25:SMTP, 53:DNS, 69:TFTP, 80:HTTP, 161:SNMP
  • 2) 客户端使用的端口号: 范围为 49152-65535。这类端口号在客户进程运行时动态分配,因此也称短暂端口号

基于 IP 协议,传输层上分别使用了两个传输协议:

  • 面向连接的传输控制协议 TCP: 提供全双工可靠逻辑信道
    • 通信双方先建立连接,然后基于此连接进行可靠数据传输;传输结束后要释放连接
    • TCP 不提供广播和多播服务
    • 为了实现可靠传输,TCP 需要增加确认、流量控制、计时器、连接管理等措施,因此它的 PDU 首部会大很多
  • 无连接的用户数据报协议 UDP: 提供无连接的不可靠服务
    • 通信双方传送数据之前不需要建立连接;接收方的传输层收到 UDP 用户数据报后,无须给发送方发回任何确认
    • UDP 提供两个附加服务:多路复用和对数据的错误检查
    • UDP 实现简单,执行速度更快,实时性好
应用 TCP/IP 应用层协议 TCP/IP 传输层协议 端口号
域名解析 DNS UDP 53
IP 地址分配 DHCP UDP 服务端 67,客户端 68
简单文件传送 TFTP UDP 69
网络管理 SNMP UDP 161
路由选择 RIP UDP
IP 多播 IGMP UDP
文件传送 FTP TCP 数据 20,控制 21
远程终端接入 TELNET TCP 23
电子邮件 SMTP TCP 25
超文本传输 HTTP TCP 80
边界网关协议 BGP TCP 179
超文本传输安全 HTTPS TCP 443

UDP

UDP 有如下优点:

  • 1) UDP 无须建立连接。因此 UDP 不会引入建立连接的时延
  • 2) 无连接状态。TCP 需要在端系统中维护连接状态,而 UDP 既不维护连接状态,又不跟踪参数
    • 因此使用 UDP 的服务器通常能够支持更多活动客户机
  • 3) 首部开销小。TCP 有 20B 首部开销,而 UDP 仅有 8B
  • 4) 没有拥塞控制。因此网络拥塞不会影响源主机的发送速率
    • 某些实时应用能容忍一些数据的丢失,但不允许有较大的时延
  • 5) UDP 支持一对一、一对多、多对一和多对多的交互通信
    • 即提供复用/分用服务

因此 UDP 通常用于一次性传输较少的应用(DNS、SNMP)或多媒体应用中

UDP 本身不保证可靠交付,但可以通过开发者根据应用需求在应用层灵活设计自己的可靠性机制

UDP 数据报分为首部和数据两部分,其中数据部分即为应用层传下来的原封不动的数据,即 UDP 是面向报文的,报文是数据处理的最小单位,UDP 在添加 8B 首部后直接交付 IP 层。

8B 首部仅有四个字段,每个字段 16-bit:

  • 源端口: 源端口号,在需要对方回信时选用,不需要时可置 0
  • 目的端口: 目的端口号,在终点交付报文给应用程序时使用
  • 长度: UDP 数据报的长度,其最小值为 8,即仅有首部
  • 检验和: UDP 提供差错检测,但是当源主机不想计算检验和时该字段也可以置 0 不使用
    • 如果检验和的计算恰好为 0,则将该字段全置 1

UDP 检验和如何计算

步骤 1:把伪首部(12B) + UDP 头部(8B) + UDP 数据 + Padding(0-1B) 连在一起

并按 16-bit(两字节)为单位分割。

步骤 2:所有 16-bit 单元做反码加法(one's complement addition)

规则是:

  • 相加溢出的进位循环加回低位(end-around carry)
  • 例如:0xFFFF + 0x0001 = 0x0000(反码加法特性)

步骤 3:若数据长度是奇数,需要补 0(padding)

最后 1 字节与 0x00 组成 16-bit

步骤 4:将整个和取反码(one's complement)

即可得到最终 checksum

步骤 5:将 checksum 写进 UDP 头部的 checksum 字段

这样接收方检验时,要求所有 16-bit 单元与 checksum 相加后结果为 0xffff,否则表示有差错

伪首部

伪首部包含 IPv4 或 IPv6 的部分内容,例如对于 IPv4 包括:

  • 源 IP 地址(4 B)
  • 目的 IP 地址(4 B)
  • 保留字段(1 B,置 0)
  • 协议号(1 B,UDP=17)
  • UDP 长度(2 B)

TCP

TCP 是在不可靠的 IP 层上实现的可靠数据传输协议,它主要解决传输的可靠、有序、无丢失和不重复问题:

  • 1) TCP 是面向连接的传输层协议,TCP 连接是一条逻辑连接
  • 2) 每一条 TCP 连接只能有两个端点,即为一对一的
  • 3) TCP 提供可靠交付服务,保证传送的数据无差错、不丢失、不重复且有序
  • 4) TCP 提供全双工通信,为此双方都设有发送缓存和接收缓存
    • 发送缓存用于暂存:①发送应用程序传送给发送方 TCP 准备发送的数据 ②TCP 已发送但尚未收到确认的数据
    • 接收缓存用于暂存:①按序到达但尚未被接收应用程序读取的数据 ②不按序到达的数据
  • 5) TCP 是面向字节流的,它将应用程序交下来的数据仅视为一连串无结构的字节流
    • 因此 UDP 报文长度由发送应用程序决定,而 TCP 报文长度则根据接收方给出的窗口值和当前网络拥塞程度来决定

TCP 报文

TCP 报文段首部长度为 20+4N Byte,后续可选选项长度为 4B 的整数倍:

cn_topic4_2.png

  • 源端口和目的端口: 各 2B,分别表示发送方和接收方使用的端口号
  • 序号: 占 4B,范围为 \(0\rightarrow2^{32}-1\),TCP 连接按字节编号,序号字段表示该报文段发送的数据的第一个字节的序号
    • 例如一报文段序号为 301,携带数据 100B,因此下一个报文段序号为 401
  • 确认号: 占 4B,期望收到对方下一个报文段的序号
    • 若确认号为 \(N\),则表示到 \(N-1\) 为止的所有数据均已正确收到
  • 数据偏移: 占 4-bit,和 IP 数据报中的数据偏移不同,该字段表示的是 TCP 数据报的首部长度,以 4B 为单位,范围为 \(5\rightarrow 15\)
    • 即 TCP 首部最小 20B,最大 60B
  • 保留: 占 6-bit,置 0
  • 紧急位 URG: URG 为 1 时紧急指针有效,此报文段数据前面存在紧急数据,应尽快传送
  • 确认位 ACK: TCP 规定,在连接建立后的所有传送报文段都必须把 ACK 置 1
  • 推送位 PSH: 发送方将 PSH 置 1,接收方收到后尽快响应,而不等到整个缓存都填满了再向上交付
  • 复位位 RST: RST 为 1 时表示连接出现严重差错,必须释放连接,然后重新建立
  • 同步位 SYN: 用于连接的建立,SYN=1 的报文段不能携带数据,但需要消耗一个序号
    • 当 SYN=1,ACK=0 时,表示这是一个连接请求报文
    • 当 SYN=1,ACK=1 时,表示同意建立连接
  • 终止位 FIN: 用于释放一个连接,FIN=1 的报文段即便不携带数据,也需要消耗一个序号
    • 当 FIN=1 时,表示发送方数据已发送完毕,要求释放传输连接
  • 窗口: 占 2B,从本报文段首部的确认号开始,接收方目前允许对方发送的数据量,以字节为单位
    • 即自己的接收窗口尺寸
    • 注意以 B 为单位,而不是以报文为单位
  • 检验和: 占 2B,和 UDP 一样检验首部和数据两部分,并且也要加上 12B 伪首部
    • 对于 TCP,伪首部中的协议字段为 6
  • 紧急指针: 占 2B,仅 URG=1 时有效,表示本报文段紧急数据的字节数
    • 即便窗口为 0,仍然可以发送紧急数据
  • 选项: 长度可变,最长 40B
    • 例如选项 Maximum Segment Size, MSS,数据字段的最大长度,此后数据的发送和重发均以 MSS 的大小进行分割

TCP 连接

TCP 连接的建立采用 C/S 模式,主动发起的应用程序为 Client,被动等待的应用程序为 Server。连接的建立需要经过三次握手

cn_topic4_3.png

  • 第一步: 客户机首先向服务器发送连接请求报文段。请求报文段的 SYN 位置 1,同时选择一个初始序号 seq=x。
    • TCP规定,SYN 报文段(SYN=1的报文段)不能携带数据,但要消耗一个序号。
    • 这时,客户机进入 SYN-SENT(同步已发送)状态。
  • 第二步: 服务器收到连接请求报文段后,如同意建立连接,则向客户机发回确认。确认报文段的 SYN 位和 ACK 位都置 1,确认号 ack=x+1,同时选择一个初始序号 seq=y。
    • 确认报文段不能携带数据,但也要消耗一个序号。
    • 这时,服务器进入 SYN-RCVD(同步收到)状态。
  • 第三步: 客户机收到确认报文段后,还要向服务器给出确认。确认报文段的 ACK 位置 1,确认号 ack=y+1,序号 seq=x+1。
    • 该报文段可以携带数据。若不携带数据,则不消耗序号,下一个数据报文段的序号仍为 x+1。
    • 这时,客户机进入 ESTABLISHED(已建立连接)状态。
    • 当服务器收到来自客户机的确认后,也进入 ESTABLISHED 状态。

成功进行以上三步后,就建立了 TCP 连接,接下来就可以传送应用层数据。TCP 提供的是全双工通信,因此通信双方的应用进程在任何时候者能发送数据。

参与 TCP 连接的两个进程都能终止该连接,TCP 连接释放的过程称为四次挥手:

cn_topic4_4.png

  • 第一步: 客户机打算关闭连接时,向服务器发送连接释放报文段,并停止发送数据,主动关闭 TCP 连接,该报文段的 FIN 位置 1,序号 seq=u,它等于前面已传送的数据的最后一个字节的序号加 1
    • FIN 报文段即使不携带数据,也要消耗一个序号。
    • 这时,客户机进入 FIN-WAIT-1(终止等待1)状态。
    • TCP是全双工的,即可以想象为一条TCP连接上有两条数据通路,发送FIN的一端不能再发送数据,即关闭了其中一条数据通路,但对方还可以发送数据。
  • 第二步: 服务器收到连接释放报文段后即发出确认。该报文段的 ACK 位置 1,确认号ack=u+1,序号 seq=v,等于它前面已传送过的数据的最后一个字节的序号加 1。
    • 然后服务器进入 CLOSE-WAIT(关闭等待)状态。
    • 客户机收到来自服务器的确认后,进入 FIN-WAIT-2(终止等待2)状态,等待服务器的连接释放报文
    • 此时,从客户机到服务器这个方向的连接就释放了,但从服务器到客户机这个方向的连接尚未关闭
  • 第三步: 若服务器已经没有要向客户机发送的数据,就向其发送连接释放报文段。该报文段的 FIN 位和 ACK 位都置 1,序号 seq=w(处于半关闭状态的服务器可能又发送了一些数据),还必须重复发送上次已发送的确认号ack=u+1。
    • 这时服务器进入LAST-ACK(最后确认)状态。
  • 第四步: 客户机收到连接释放报文段后,必须发出确认,之后进入 TIME-WAIT(时间等待)状态。该报文段的 ACK 位置 1,确认号 ack=w+1,序号 seq=u+1。
    • 服务器收到该确认报文段后就进入 CLOSED(连接关闭)状态。
    • 客户机进入 TIME-WAIT 状态后,还要经过时间等待计时器设置的时间 2MSL(Maximum Segment Lifetime,最长报文段寿命)后,才进入 CLOSED 状态。

Info

若服务器收到连接释放请求后不再发送数据,则从客户机发出 FIN 报文段时刻算起,客户机释放连接的最短时间为 1RTT+2MSL,服务器释放连接的最短时间为 1.5RTT。

超时和冗余 ACK 两个事件会导致 TCP 对报文段进行重传

  • <1> 超时 TCP 每发送一个报文段,就对该报文段设置一个超时计时器。计时器超时但仍未收到确认,则重传该报文段
    • 超时计时器重传时间的设置使用自适应算法,它记录报文段往返时间 RTT 的加权平均值 RTTS,该值会随着新测量 RTT 样本值的变化而变化。而超时重传时间 RTO 应设置略大于 RTTS 即可
  • <2> 冗余确认 发送方收到对同一个报文段的 3 个冗余 ACK 时,就认为这个被确认报文段之后的报文段丢失,这种技术也成为快速重传
    • TCP 规定每当比期望序号大的失序报文段到达时,就发送一个冗余 ACK,指明下一个期待字节的序号
    • 例如发送方 A 发送序号 1, 2, 3, 4, 5 的报文段,其中 2 丢失。此时 3, 4, 5 对于接收方 B 来说就是失序报文段,因此 B 向 A 发送三个冗余 ACK,指明自己期望接收 2 号报文段

TCP 流量控制与拥塞控制

流量控制用于匹配发送方的发送速率和接收方的读取速率,通过滑动窗口机制来实现。

接收方会维持一个接收窗口 rwnd,它根据当前接收缓存的大小动态调整接收窗口大小,并将该值放入 TCP 报文段首部的“窗口”字段。而发送方的发送窗口不能超过接收方给出的接收窗口值,以限制发送方向网络注入报文的速率。

cn_topic4_6.png

TCP 为每个连接设有持续计时器,当接收到对方的零窗口通知,就启动该计时器。若计时器超时,向对方发送一个零窗口探测报文,对方确认该探测报文时返回目前的窗口值。若窗口仍然为 0,重置持续计时器。

和数据链路层流量控制的区别

传输层实现的是两个进程之间的流量控制,并且窗口大小可以动态变化;数据链路层实现的是两个相邻中间节点的流量控制,且窗口大小不能动态变化

拥塞控制是为了防止过多的数据注入网络,保证网络中路由器或链路不过载。

发送方既要考虑接收方的接收能力,又要从全局考虑不使网络堵塞。因此发送方要维持一个拥塞窗口 cwnd,其大小根据网络拥塞程度动态变化。而发送窗口的上限值则取 rwnd 和 cwnd 中较小的那一个,即:

\[ \text{发送窗口上限值}=\min [rwnd, cwnd] \]

慢开始和拥塞避免

慢开始指刚开始发送数据时,先发送少量数据探测,然后由小到大增大 cwnd(指数增长);拥塞避免指的是每经过一个 RTT 就对 cwnd 加 1(线性增长),使网络不容易出现拥塞。

我们通常设置一个门限 ssthresh:

  • 当 cwnd < ssthresh 时,使用慢开始算法
  • 当 cwnd > ssthresh 时,使用拥塞避免算法
  • 只要发送方判断网络出现拥塞(未能按时收到确认)时,就将门限 ssthresh 减为当时 cwnd 值的一半(但不能小于 2),然后将 cwnd 置 1

cn_topic4_7.png

指数增长的下一个值大于门限时,向下取到门限值并开始拥塞避免

快重传和快恢复

有时个别报文段会在网络中丢失,但实际上网络并未拥塞。若发送方迟迟收不到确认,就会产生超时,并误认为网络发生了拥塞,导致发送方错误地启动慢开始算法。

因此我们使用快重传算法让发送方尽早知道发生了个别报文段的丢失。接收方不再只是发送自己数据时才进行捎带确认,而是收到了报文段后立即发送确认。此时收到失序的报文段就会发送冗余确认,发送方一旦连续收到 3 个冗余 ACK,就立即重传相应报文段,而不是等超时计时器超时再重传。

快恢复算法指的是,当发送方连续收到 3 个冗余 ACK 时,会将门限 ssthresh 调整为当前 cwnd 的一半的同时,仅将 cwnd 也调整为当前 cwnd 的一半,然后开始执行拥塞避免算法。这是因为发送方认为现在的网络很可能没有发生严重拥塞。

cn_topic4_8.png

Comments: