【计网】运输层详解

1.The model of Transport-layer services

运输层为运行在不同主机上的进程之间提供了通信,传输层协议是在终端中执行的,而网络层是主机之间的通信,传输层依赖于网络层服务,但又能增强网络层的服务

发送端:将应用程序消息分解为分段,传递到网络层 rcv 端:将段重新组合成消息,传递到应用层

TCP和UDP的分组统称为segment报文段,网络层的分组叫做datagram数据报

协议概述

TCP:

  • 可靠、有序的交付
  • 拥塞控制
  • 流控制
  • 连接设置

UDP

  • 不可靠、无序递送
  • “尽力而为”的 IP 的简洁扩展
  • 不可进行延迟保证、带宽保证

2.multiplexing/demultiplexing (多路复用/分解)

一个进程有一个或多个socket套接字
multiplexing多路复用:从源主机的不同socket收集数据块,为每个数据块封装上首部header信息,生成报文段传输网络层
demultiplexing多路分解:收到网络层传来的报文段之后,根据首部解析并将当中的数据块交付给正确的socket

每个数据报都有源 IP 地址、目标 IP 地址,每个数据报携带 1 个传输层段,每个segment都有源端口号、目标端口号,主机使用IP 地址和端口号将分段定向到适当的套接字

2.1 UDP无连接的多路分解 Connectionless demultiplexing

由双元组标识的 UDP 套接字: (dest IP 地址,dest 端口号)

  • 当主机接收到 UDP 段时:
    • 检查网段中的目标端口号
    • 将 UDP 段定向到具有该端口号的套接字
  • 具有不同源 IP 地址和/或源端口号的 IP 数据报,这些数据报定向到同一套接字

image.png

2.2 TCP的多路分解 Connection-oriented demultiplexing

4 元组标识的 TCP 套接字: 源 IP 地址 源端口号 dest IP 地址 dest 端口号
recv 主机使用所有四个值将段定向到适当的套接字

  • 服务器主机可能支持许多并发 TCP 套接字
    • 每个套接字由其自己的 4 元组标识 Web 服务器,源ip或源端口号不同也将被定向到不同socket
  • 对每个连接客户端具有不同的套接字
    • 非持久性 HTTP 将为每个请求提供不同的套接字

image.png

3.UDP(User Datagram Protocol)用户数据报协议

为什么有 UDP?

  • 无需连接建立(这可能会增加延迟),不用三次握手,没有建立连接的时延,是DNS建立在UDP之上的主要原因:
  • 发送方、接收方无连接状态,不需要维护连接状态
  • 分组首部开销小,TCP有20字节首部开销,UDP仅仅8字节
  • 无拥塞控制:UDP 可以根据需要快速blast,一些应用需要最短时延,可以忍受一些数据丢失

实际应用:

  • 通常用于流式传输多媒体应用程序: 容错性 速率敏感
  • 其他 UDP 用途:域名解析(DNS) 断续器(SNMP)
  • 通过 UDP 进行可靠传输:在应用层实现可靠性,如QUIC

UDP报文段结构:
header共4个字段,每个字段2字节,因此header总共8字节
length表示UDP报文段字节数,包含header的长度
checksum进行差错检验
image.png

UDP checksum
检验传输段是否产生错误,但不能保证没错

发送端: 将段内容视为 16 位整数序列
校验和:段内容的加法(1 的补码和)
发送方将checksum值放入 UDP的checksum字段

接收端:检查计算的校验和是否等于校验和字段

如果产生进位,把进位加到末位,然后取反得到Checksum的值
image.png

4.reliable data transfer(rdt) 可靠数据传输

4.1 rdt 1.0

假设底层信道完全可靠,没有位错误和数据丢失

直接发送方发数据给底层信道,接收方从底层信道读取

下面的图,横线上面表示引起变化的事件,横线下面代表事件变化后采取的动作(函数实现)

发送端等待上层的调用(应用层传数据过来)然后发送数据,接收端等待下层的调用(网络层传数据报过来)然后发送数据
image.png

4.2 rdt 2.0

假设:可能会发生bit错误、但起码不会丢包

解决:

  • 错误检测:checksum以检测位错误
  • 如何从错误中恢复:接收方反馈和重传机制 ARQ(Automatic Repeat reQuest)自动重传请求协议
    • 确认 (ACK):接收方明确告诉发送方 pkt 接收正常
    • 否定确认 (NAK):接收方明确告诉发送方 pkt 有错误 发件人在收到 NAK 时重传
      rdt2.0 中的新机制(相比rdt1.0): 错误检测、接收器反馈:控制消息 (ACK,NAK)、重传

这是一种停等协议(stop-and-wait):
发送端等待上层的调用然后发送数据,然后等待ACK和NAK分组响应,收到响应后如果ACK继续等待上层调用,如果NAK则重传,继续等待ACK或NAK。
接收端等待下层的call,收到call后检验数据包,根据情况返回ACK或NAK分组
image.png

4.2.1 rdt 2.1

问题:ACK和NAK数据包损坏怎么办,不能简单重传
处理方式:让发送方给每个packet加序列号Seq,因此接收方只要检查序号就能判断是否为重传

发送方的状态图:反映了发送和接受的分组序号Seq,Seq只需要1bit
等待来自上层的Seq为0的分组
等到Seq为0的ACK和NAK
等待来自上层的Seq为1的分组
等到Seq为1的ACK和NAK

image.png
接收方状态图:根据发送的packet的Seq不同返回不同的ACK/NAK
image.png

4.2.2 rdt 2.2

没有NAK,只有ACK,因为发送方检查收到的ACK分组中的Seq就能替代NAK功能,接收到2个序号一样的ACK(冗余ACK),就知道接收方没有正确接受该序号之后的分组,然后重传

状态图:

image.png

4.3 rdt 3.0

假设:除了bit错误之外,底层信道还会丢包(数据包,ACK包)

这里让发送方来负责检测和恢复丢包

解决方案:超时(timeout)

  • 发送方等待“合理”的 ACK 时间,如果此时未收到 ACK,则重新传输
  • 如果 pkt(或 ACK)只是延迟(未丢失):
    • 重新传输将是重复的,但是使用 seq 已经处理了这个问题
    • 接收方必须指定正在 ACKed 的 pkt 的 seq
      需要倒数计时器(countdown timer)

如下图,增加了timeout和用于计时的start_timer、stop_timer
image.png

超时重传机制如图所示
image.png

由于分组序号Seq在0和1之间交替,rdt 3.0有时候也称作比特交替协议(alternating-bit protocol)

性能问题:
假设信道发送速率1 Gbps,包含header和数据的分组长度1000字节(8000 bits),则发送一个分组进入该1 Gbps链路所需时间:

image.png
如上图,发送方忙于发送的时间很少,利用率0.00027,主要是由停等方式造成的

4.4 流水线(pipelining)

发送方不需要等待ACK响应,接下去发送分组

实现:

  • 增加序列号Seq的范围
  • 在发射方和接收方处有缓存
  • 要解决损坏、丢失、超时问题,通过Go-Back-N(GBN回退N步), Selective Repeat(SR选择重传)

4.4.1 Go-Back-N(GBN回退N步)

下面为Seq字段的结构,绿色代表已确认的分组,黄色代表未确认但已发送,蓝色代表即将发送,白色部分不能被使用,N为窗口长度,若Seq字段长度为k bits,则序号空间可看作长度为 2 k 2^k 2k的环
image.png
发送方动作必须响应三种类型的事件:

  • 上层调用。上层调用rdt-send(),检查发送窗口是否已满(是否已有N个已发送但是未确认的分组),未满即可调用,已满可用超时、缓存、同步机制等策略。
  • 收到一个ACK。对序号为n的分组,进行累积ACK
  • 超时。重传序号为n即以上的分组,即重传所有已发送但未确认的
    接收方动作:
  • ACK-only:始终为正确接收的 pkt 发送具有最大顺序 seq 的 ACK
    • 可能会生成重复的 ACK
    • 只需要记住预期的seqnum
  • 对于无序的包:
    • 丢弃(不进行缓存,因为会重传所以没必要)
    • 依然发送之前最大顺序的ACK
      具体表现:

image.png

4.4.2 选择重传SR(Selective repeat)

发送方:绿色已确认,蓝色即将发送,黄色发送了未确认
接收方:红色失序、但是已确认所以先缓存,等待其他顺序更小的;蓝色是已接受;灰色代表期待接收,但没收到
image.png

发送方动作:

  • 从上层收到数据: 如果在窗口中检查到下一个可用的seq,则发送pkt
  • timeout(n)超时:
    • 重新发送 pkt n(第n个分组)
    • 重新启动计时器
  • 收到ACK:
    • 若收到[sendbase,sendbase+N] 窗口中的 ACK(n),将 pkt n 标记为已接收
    • 如果是最小的未确认pkt(分组序号等于send_base),则将窗口基序号向前移动到下一个未确认的ACK。
    • 如果窗口移动了并且有序号落在窗口内未发送分组,则发送这些分组

接收方动作:

  • pkt n 的seq in [rcvbase, rcvbase+N-1] :(在窗口当中)
    • 发送ACK(n)
    • 如果是无序的(不按照预期顺序):放入缓冲区
    • 如果正常按顺序:交付(也交付缓冲的、有序的 pkts),提前窗口到下一个尚未收到的 pkt
  • pkt n 的seq in [rcvbase-N,rcvbase-1] :(在最小seq之前)
    • send ACK(n),即使以前已经确认过,否则发送方窗口滑动不了
  • 其他情况:忽视分组

具体表现:
图中pkt2丢包,接收端窗口最小序号rcvbase停在2,发送端由于没收到ACK2,所以sendbase停在2。
发出pkt5后,发送端窗口已满,超时,重传pkt2,接收端收到pkt2后返回ACK2马上移动窗口,发送端收到ACK2也移动窗口
image.png

如果序号空间太小,可能无法判断是新发送的数据还是之前的重传,因此窗口长度必须不大于序号空间大小的一半

5.TCP: Transmission Control Protocol 传输控制协议

5.1 特点

  • 点对点: 一个发送方,一个接收方(所以不能“广播”)
  • 可靠、按顺序排列的字节流: 没有“信息边界”
  • 流水线: TCP 拥塞和流量控制,设置窗口大小
  • 具有发送和接收缓冲区
  • 全双工数据(full-duplex data):
    • 同一连接中的双向数据流 (bi-directional data flow)
    • MSS(Maximum Segment Size):最大报文段长度(应用层数据),通常根据MTU(Maximum Transmission Unit)来设置,由于MSS单指应用层数据段最大长度,因此有 M S S = M T U − T C P / U D P h e a d e r − I P h e a d e r MSS = MTU - TCP/UDP header - IP header MSS=MTUTCP/UDPheaderIPheader,例如以太网和PPP链路层协议MTU=1500,TCP报文的MSS=1460,UDP的MSS=1472
  • 面向连接(connection-oriented): 握手(交换控制消息),以初始化发送方,接收方在数据交换前的状态
  • 流量控制: 发送方不会发过多数据淹没接收方

5.2 TCP报文段结构

image.png

  • Seq. #'s: 段数据中第一个字节的字节流“编号”(因为不是按segment计数,是按byte计数)
  • ACKs:
    • ACK是主机正在等待的数据的下一字节的Seq
    • 累积确认,累积确认到流中至第一个丢失为止的字节
  • Q:接收方如何处理无序段 A:TCP规范没有说,取决于实现者

5.3 RTT(Round Trip Time)往返时间的估计与超时

  • 估计RTT的计算,典型的α值为0.125
    E s t i m a t e d R T T = ( 1 − α ) ∗ E s t i m a t e d R T T + α ∗ S a m p l e R T T EstimatedRTT = (1- \alpha)*EstimatedRTT + \alpha*SampleRTT EstimatedRTT=(1α)EstimatedRTT+αSampleRTT
  • 样本RTT与估计RTT的偏差程度计算,典型的β值为0.25
    D e v R T T = ( 1 − β ) ∗ D e v R T T + β ∗ ∣ S a m p l e R T T − E s t i m a t e d R T T ∣ DevRTT = (1-\beta)*DevRTT +\beta*|SampleRTT-EstimatedRTT| DevRTT=(1β)DevRTT+βSampleRTTEstimatedRTT
  • 则可算出超时间隔
    T i m e o u t I n t e r v a l = E s t i m a t e d R T T + 4 ∗ D e v R T T TimeoutInterval = EstimatedRTT + 4*DevRTT TimeoutInterval=EstimatedRTT+4DevRTT

5.4 TCP reliable data transfer(可靠数据传输)

可靠数据传输确保一个进程从接收缓存中读取的数据流是无损坏、无间隙、非冗余和按顺序的数据流,即收到的字节流与发出时相同

TCP 在 IP 不可靠的服务之上创建 rdt(reliable data transfer)服务

  • 流水线
  • 累积ACK
  • 缓存无序的segment
  • TCP 使用单一的重传计时器(计时器管理开销大)

重传由以下因素触发:

  • 超时事件
  • 重复ACK

TCP发送端3个与发送或重传有关的事件:

  • 收到来自应用层的数据:
    • 创建区段seq #
    • seq # 是段中第一个数据字节的字节流数
    • 启动计时器(如果尚未运行)(将计时器视为最旧的未确认段)
    • 定时器过期间隔:超时间隔
  • 超时:
    • 重传导致超时的段 (只重传第一个,如果后面的也超时就后面再说,因为只有一个计时器)
    • 重启计时器
  • Ack rcvd: 如果确认以前未确认的段
    • 更新已知已确认的内容
    • 启动计时器(如果有未完成的段)

三种比较特殊的情况:

  • 因为ACK丢失,时间间隔内发送端没有收到ACK,重传
  • 因为ACK在超时间隔过后发送端才收到,而引起超时的段的重传已发送,收到的ACK是后面累积过后的ACK
    image.png
  • 第一个ACK丢失,但是第二个发送端在超时间隔内收到了,由于ACK比预想中的大,Host A知道先前的包Host B也收到了,因此没有重传

image.png

TCP接收端产生ACK的事件和过程:

事件TCP接收方动作
所期望的seq到达,并且期望seq之前的数据都已经确认(发了ACK)delayed ACK。等另一个按序报文段500ms,如果没到就发一个ACK
所期望的seq到达,但前面还有一个按序报文段等着发ACK立即发送单个累计后的ACK,发送端收到后同时确认两个报文段
比期望seq大的到达发一个冗余(duplicate)ACK,指出下一个期待的byte的seq
能部分或者完全填充之前的seq数据间隔报文段到达如果是未确认的最小seq,马上发ACK

5.5 Fast Retransmit 快速重传

快速重传:在该报文段计时器过期之前重新发送报文段,而不等到超时

如果发送方收到相同数据的 3 个 ACK,则确定这个报文段后面发送的那一个报文段没收到,进行快速重传那个报文段。

选择确认(Selective Acknowledgement)类似于选择重传

5.6 Flow Control 流量控制

背景:TCP 连接的接收端具有接收缓冲区,但可能因为应用层可能从下层读取信息很慢而溢出(发送端不需要担心类似问题),所以有了流量控制(因为UDP没有,所以溢出就丢失了)

image.png

流量控制是一个速度匹配服务:将发送速率与接收应用的消耗速率匹配

动态设置接收窗口空间:
LastByteRcvd表示网络中到达并且放入主机B缓存的数据流最后一个字节编号
LastByteRead是主机B应用层从缓存读出的最后一个字节的编号
式子表示:
窗 口 空 间 = 缓 存 可 用 空 间 − 已 到 达 数 据 空 间 + 已 读 取 数 据 空 间 窗口空间=缓存可用空间-已到达数据空间+已读取数据空间 =+
R c v W i n d o w = R c v B u f f e r − [ L a s t B y t e R c v d − L a s t B y t e R e a d ] RcvWindow = RcvBuffer-[LastByteRcvd - LastByteRead] RcvWindow=RcvBuffer[LastByteRcvdLastByteRead]
后两个都是变量,窗口空间跟着这两个变量的变化而变化

5.7 TCP Connection Management 连接管理

5.7.1 TCP三次握手(建立连接)

  • 步骤 1:客户端主机将 TCP SYN报文段(SYN置为1就叫做SYN报文段)发送到服务器
    • 客户端随机指定初始seq#放到SYN报文段的seq里面
    • 不含应用层数据
  • 步骤 2:服务器主机接收SYN,使用SYNACK报文段回复
    • server分配缓冲区
    • server随机指定初始seq#放到SYNACK报文段的seq里面
    • SYNACK中的ACK = client_isn(客户端指定的初始Seq) + 1
  • 步骤 3:客户端接收SYNACK,使用ACK报文段回复,此时SYN置0,其中可能包含应用层数据

扩展:SYN flood attack,使用cookie机制防御(可以深入了解)

5.7.2 关闭连接

  • 步骤 1:客户端系统将 TCP FIN 控制报文段(即FIN位被置1的报文段)发送到服务器
  • 步骤 2:服务器接收 FIN,使用 ACK 进行回复。关闭连接,发送 FIN报文段
  • 步骤 3:客户端收到FIN报文段,使用ACK回复。
  • 步骤 4:服务器,接收ACK,连接关闭。

image.png

5.7.3 客户端状态转移图

image.png

5.7.4 服务端状态转移图

image.png

6.Congestion Control 拥塞控制

非正式的定义:“太多的来源发送太多的数据,太快,网络无法处理” ,不同于流量控制

事件:

  • 丢失数据包(路由器的缓冲区溢出)
  • 长时间延迟(在路由器缓冲区中排队)

6.1 拥塞的原因与代价分析

第1种情况(scenario 1):两个发送方、一个路由器、路由器缓存无限,无重传
λ i \lambda_i λi代表主机A向路由器发出数据的速率 λ i \lambda_i λi字节/秒
假设B与A相同的方式运行
C、R代表共享链路的容量
image.png
第2种情况(scenario 2):有丢包重传,路由器缓存有限
λ i ′ \lambda'_i λi代表主机A向路由器发出数据的速率加上重传数据的速率
image.png

  • a图表示不丢包的情况
  • b图仅在丢失时重传(R/3初始数据,R/6重传数据是所有包都丢失的极端情况)
  • c图提前发生超时,产生延迟(未丢失)数据包的不必要重传,所有包都提前发生超时则每个分组都通过链路两次

image.png

第3种情况(scenario 3):4个发送端、多跳路径、有超时重传
另外一种开销:第一跳路由器转发的分组在第二跳被丢弃
image.png

6.2 拥塞控制方法

端到端(end-end)拥塞控制:

  • 运输层没有来自网络层的明确反馈
  • 从端系统观测到的损失、延迟推断出拥塞
  • TCP采取这种方法,因为IP层不会向端提供有关网络拥塞的反馈

网络辅助拥塞控制:

  • 路由器向端系统提供反馈
  • 单个bit(SNA、DECbit、TCP/IP的ECN(explicit congestion notification)、ATM)来指示拥塞

扩展样例:ATM ABR congestion control

6.3 TCP拥塞控制

发送方限制发送速率的手段:
TCP跟踪一个拥塞窗口(congestion window),该变量表示为cwnd,对TCP发送方发送的速率进行限制
并且发送方中未确认(没收到ACK)的数据量不会超过cwnd和rwnd(接收窗口)最小值
L a s t B y t e S e n t − L a s t B y t e A c k e d < = m i n { c w n d , r w n d } LastByteSent-LastByteAcked <= min\{cwnd,rwnd\} LastByteSentLastByteAcked<=min{cwnd,rwnd}
先假设rwnd无限大,则
L a s t B y t e S e n t − L a s t B y t e A c k e d < = c w n d LastByteSent-LastByteAcked <= cwnd LastByteSentLastByteAcked<=cwnd
且发送速率 r a t e = c w n d / R T T rate = cwnd / RTT rate=cwnd/RTT

发送方如何感知拥塞:

  • 丢包事件 = 超时3 个冗余ACKs(即一共收到4个相同ACK)
  • TCP 发送方在丢失事件后降低速率 (本质为减少CongWin)

自计时(self-clocking):

  • 发送方收到以前未确认报文段的ACK,判断为恢复正常并增大发送速率
  • 带宽探测:根据收到ACK的速率增长窗口长度,收到ACK快则增长快

6.3.1 慢启动(Slow Start)

当连接开始时,以指数级速度(乘2)快速增加速率,直到第一次丢包事件

实现:

  • 开始时拥塞窗口为1MSS(Maximum Segment Size,最大报文长度)
  • 收到每个ACK就增加1MSS的CongWin(拥塞窗口),实际上就是每一次RTT后cwnd都翻倍 c w n d ∗ = 2 cwnd*=2 cwnd=2
    image.png

慢启动的结束:

  • 慢启动期间如果出现丢包,把ssthresh(慢启动阈值)设置为cwnd/2,拥塞窗口重新设置为1MSS,重新进行慢启动
  • cwnd到达或超过ssthresh时,结束慢启动(不再将cwnd乘2)进入拥塞避免模式
  • 检测到3个冗余ACK,执行快速重传,cwnd值减半即cwnd/=2,ssthresh设置为cwnd/2,进入快速恢复状态

6.3.2 拥塞避免(TCP Congestion Avoidance)

在拥塞避免模式下,每一次RTT拥塞窗口的值增加1MSS c w n d + = 1 M S S cwnd+=1MSS cwnd+=1MSS

拥塞避免的结束:

  • 超时,把ssthresh(慢启动阈值)设置为cwnd/2,拥塞窗口重新设置为1MSS,进入慢启动
  • 检测到3个冗余ACK,执行快速重传,cwnd值减半即cwnd/=2,ssthresh设置为cwnd/2,进入快速恢复状态

6.3.3 快速恢复(Refinement)

cwnd值减半(但不会小于1MSS)后,每收到一个冗余ACK,cwnd加1MSS c w n d + = 1 M S S cwnd+=1MSS cwnd+=1MSS

即使收到3个冗余ACK,cwnd仍旧正常加3MSS

快速恢复的结束:

  • 超时,把ssthresh(慢启动阈值)设置为cwnd/2,拥塞窗口重新设置为1MSS,进入慢启动
  • 收到丢失报文段的正常ACK,即进入拥塞避免

image.png

6.3.4 TCP拥塞控制回顾

方法:提高传输速率(窗口大小),探测可用带宽,直到发生损失

  • 加性增(Additive increase):每RTT增加1 MSS,直到检测到损失
  • 乘性减(Multiplicative decrease):亏损后将CongWin减到一半

image.png

总结:

  • 当CongWin低于阈值时,发送方处于慢启动阶段,窗口呈指数级增长。
  • 当CongWin高于阈值时,发送方处于拥塞避免阶段,窗口线性增长。
  • 当收到3个冗余 ACK 时,“阈值”设置为 CongWin/2,将“CongWin”设置为“阈值”。
  • 发生超时时,阈值设置为 CongWin/2,CongWin 设置为 1 MSS。

image.png

6.3.5 TCP吞吐量(throughput)

作为窗口大小和RTT的函数,整个TCP的平均值是多少?假设忽略慢启动(因为只有刚开始建立连接为慢启动)
设 W 为发生损失时的窗口大小,则吞吐量为 W ∗ M S S / R T T W*MSS/RTT WMSS/RTT
在丢失后,窗口下降到 W/2,吞吐量下降到$ W*MSS/2RTT$
由于拥塞控制阶段线性增加,可以使用平均,整个过程中的平均吞吐量: 0.75 W ∗ M S S / R T T 0.75 W*MSS/RTT 0.75WMSS/RTT

6.3.6 公平性

公平性目标:如果 K个 TCP 会话共享相同的带宽 R 瓶颈链路,则每个会话的平均速率应为 R/K

两个相互竞争的sessions: 线性增加使斜率趋近为 1,乘法减少只是按比例降低吞吐量
所以在过程中,越来越趋近于等分带宽
image.png

公平性和 UDP:

  • 多媒体应用程序通常不使用 TCP 因为不希望速率受到拥塞控制的限制
  • 所以改用 UDP: 以恒定速率传输音频/视频,可以容忍数据包丢失

公平性和并行 TCP 连接:
没有什么可以阻止应用程序在2个主机之间打开并行连接。比如Web 浏览器
示例:
假设开始时速率R的链接支持着9个连接;
新应用程序要求1个TCP,获得速率R / 10
新应用程序要求11个TCP,得到R / 2!

7.扩展协议

QUIC、TCP ECN、TFRC(TCP友好控制)、DCCP、SCTP、TFRC

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值