【计算机网络】传输层

【计算机网络】传输层

传输层协议概述

传输层协议为运行在不同host上的进程提供了一种逻辑通信机制。使得端到端不需要关心中间的过程,直接可以看作是可以通信的进程。

网络层和传输层的区别

网络层是为主机之间提供逻辑通信,运输层为应用进程之间提供端到端的逻辑通信。

传输层对收到的报文进行差错检测,IP数据报首部中的校验和字段只检验头部是否出现差错,而不检查数据部分。

传输层位于网络层之上,依赖于网络层服务,对网络层服务进行增强,向高层屏蔽了下面网络核心的细节。它使应用进程看见的就好像在两个运输层实体之间有一条端到端的逻辑通信信道。

传输层的协议

两个对等运输实体在通信时传送的数据单元叫做运输协议数据单元TPDU,但在TCP/IP体系中,TCP叫报文段,UDP叫数据报。

  • UDP
    • 不需要先建立连接
    • 远程主机的传输层在收到UDP报文后,不需要给出任何确认
    • 不可靠的交付服务
    • 基于“尽力而为”的网络层,没有做可靠性方面的扩展
  • TCP
    • 可靠、按序的交付服务
    • 拥塞控制
    • 流量控制
    • 连接建立、数据报传送结束后要释放连接
    • 额外开销:确认、流量控制、计时器、连接管理

两种服务均不保证:延迟、带宽

常见应用使用的协议

传输层的端口

在协议栈层间的抽象的协议端口是软件端口,硬件端口是不同硬件设备进行交互的接口,而软件端口是应用层的各种协议进程与传输实体间进行层间交互的一种地址。端口号只具有本地意义。

两大类端口号:

  • 服务器使用的端口号
    • 熟知端口号
    • 系统端口号
  • 客户端使用的端口号

多路复用和多路分用

如果某层的一个协议对应直接上层的多个协议/实体,则需要复用/分用。

接收端进行多路分用:传输层依据头部信息将接收到的Segment交给正确的Socket,即不同的进程
发送端进行多路复用:从多个Socket接收数据,为每块数据封装上头部信息,生成Segment,交给网络层。

分用的流程:

  • 主机接收到IP数据报
    • 每个数据报携带源IP地址,目的IP地址
    • 每个数据报携带一个传输层的段
    • 每个段携带源端口号和目的端口号
  • 主机收到Segment后,传输层协议提取IP地址和端口号信息,将Segment导向相应的Socket
    • TCP更多处理

无连接分用:

  • 利用端口号创建Socket
  • UDP的Socket用二元组标识(目的IP地址,目的端口号)
  • 主机收到UDP段后
    • 检查段中的目的端口号
    • 将UDP段导向绑定在该端口号的Socket
  • 来自同源的IP地址和端口号的IP数据报被导向同一个Socket
  • 源端口号提供“返回地址”,返回数据

面向连接的分用:

  • TCP的Socket的四元组标识
    • 源IP地址
    • 源端口号
    • 目的IP地址
    • 目的端口号
  • 接收端利用所有的四个值将Segment导向合适的Socket
  • 服务器可能同时支持多个TCP Socket
  • Web服务器为每个客户端开不同的Socket
端口分用

用户数据包协议UDP

UDP概述

用户数据包协议UDP只在IP的数据报服务上增加了很少一点的功能,就是复用和分用的功能记忆差错检测功能。

UDP的特点

  • 无连接
    • 不需要握手
    • 每个UDP段的处理独立于其他段
    • 减少了开销和发送数据之前的时延
  • "尽力而为"服务
    • 丢失
    • 非按序到达
    • 不需要维持复杂的连接状态表
  • 面向报文
    • 对应用层的报文,添加首部后就向下交付给IP层,UDP对于应用层的报文既不合并,也不拆分,保留这些报文的边界。应用层给多长的报文,UDP就照发,即一次发送一个报文。交付时也是一次交付一整个报文。因此应用层需要选择合适大小的报文,若报文太长,IP层在发送时可能要进行分片,会降低IP层的效率
  • 没用拥塞控制
    • 网络的拥塞不会使源主机的发送速率降低,允许丢失一些数据
  • UDP支持一对一、一对多、多对一和多对多的交互通信
  • UDP首部开销小
    • 只有8字节,TCP20字节
UDP面向报文

UDP的首部格式

UDP有两个字段:数据字段和首部字段。

首部字段有8字节:

  • 源端口
  • 目的端口
  • 长度
  • 校验和:检测UDP用户数据包在传输中是否有错,有错就丢弃
UDP首部

如果接收方UDP的目的端口号不正确,就丢弃该报文,并有ICMP发送“端口不可达“差错报文给发送方。

UDP 校验和(checksum)

目的:检查UDP段在传输中是否发生错误(如位翻转)

发送方:

  • 将段的内容视为16-bit整数
  • 校验和计算:计算所有整数的和,进位加在和的后面,将得到的值按位求反,得到校验和
  • 发送方将校验和放入校验和字段

接收方:

  • 计算所收到段的校验和
  • 将其与校验和字段进行对比
    • 不相等:检测出错误
    • 相等:没有检测出错误(但有可能有错误)
计算校验和

TCP 概述

TCP主要特点

  • 面向连接
    • 必须建立连接和释放连接
  • 每条TCP连接只能有两个端点,每条TCP连接只能是点对点
  • TCP提供可靠交付的服务
    • 无差错
    • 不丢失
    • 不重复
    • 按序到达
  • 全双工通信
    • TCP允许通信双方的应用进程在任何时候都能发送数据,TCP连接的两端都舍友发送缓存接收缓存
    • 发送时,应用程序在把数据传送给TCP的缓存后,就可以做自己的事情,而TCP在合适的时候把数据发送出去。接收时同理。
  • 面向字节流
    • ”流“指的是流入到进程或从进程流出的字节序列。
    • 虽然应用程序和TCP的交互式一次一个数据块(大小不等),但TCP把应用程序交下来数据看成仅仅是一连串的无结构的字节流。TCP并不知道所传送的字节流的含义。
    • TCP不保证接收方收到的数据块和应用方所发出的数据块具有对应大小的关系(例如发送方发给TCP10各数据块,但接收方TCP可能只用了4个数据块就把所有字节流交付给上层了)
    • 注意:TCP连接是一条虚连接而不会一条真正的物理连接。
    • TCP对应用进程一次把多长的报文发送到TCP的缓存中是不关心的,TCP根据对方给出的窗口值和当前网络拥塞程序决定报文段包含多少字节(UDP的报文长度直接由应用进程决定)。如果TCP缓存的数据块太长,TCP就可以把它划分短一些再传送,如果进程只发送一个字节,TCP也会等待积累有足够字节后再构成报文段发送出去。
TCP面向流的概念

TCP连接

TCP 把连接作为最基本的抽象。

每条TCP连接都有两个端点,这两个端点叫做套接字socket。端口号拼接到IP地址即构成了socket。

可靠传输的工作原理

理想传输条件的两个特点:

  • 传输信道不产生差错
  • 不管发送方以多块的速率发送数据,接收方总是来得及处理收到的数据

停止等待协议

”停止等待“就是每发送完一个分组就停止发送,等待对方的确认,在收到确认后再发送下一个分组。

无差错情况
停止等待协议
出现差错

如果接收方接收到数据时,检测出了错误,就丢弃数据,其他什么都不做,也可能是数据报在传输过程中丢失了。这两种情况,接收方不发送任何信息。

可靠传输协议是这么设计的:发送方超过一段时间仍然没有收到确认消息,就认为刚发送的分组丢失了,因而重传前面发送过的分组,这就是超时重传

完成超时重传,就要每发送完一个分组设置一个定时器。如果在超时计时器到期之前就收到了对方的确认,就撤销已设置的超时计时器。

注意点:

  • 发送方发送完一个分组后,必须暂时保留已发送的分组的副本(为发生超时重传时使用),只有在收到相应的确认后才能清除暂时保留的分组副本
  • 分组和确认分组都必须进行编号,这样才能明确是哪一个发送出去的分组收到了确认,而哪一个没收到。对于等待停止协议,只要用1位编号(0和1)即可,可重复使用,但这种编号不能保证可靠传输。
  • 超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些。如果太长,通信效率就很低,太短,就产生必须要的重传,浪费网络资源。
确认丢失和确认迟到

确认丢失时,发送方重传数据,接收方丢失这个重复的分组,并且要再次向发送方发送确认

确认丢失和确认延迟

上诉的这种可靠传输协议称为自动重传请求ARQ

信道利用率

停止等待协议的优点就是简单,但缺点就是信道利用率低。

流线线协议

  • 允许发送方在收到ACK之前连续发送多个分组
    • 更大的序列号范围
    • 发送方和接收方需要更大的存储空间以及缓存分组

连续ARQ协议、滑动窗口协议

为提高传输效率,可采用流水线传输,采用连续ARQ协议滑动窗口协议,滑动窗口协议较复杂,是TCP协议的精髓,后面介绍。

连续ARQ协议,发送方维持发送窗口,意义是:位于发送窗口内的5个分组都可以连续发送出去,而不需要等待对方的确认。这样,信道利用率就提高了。发送方每收到一个确认,就把发送方窗口向前滑动一个分组的位置。

连续ARQ协议原理

接收方一般采用累积确认的方式,接收方不必对收到的分组逐个发送确认,而可以在收到几个分组后,对按序到达的最后一个分组发送确认,表示到这个分组为止的所有分组都已正确收到了。

累计确认优点容易实现,缺点不能向发送方反映出接收方已经确认收到的所有分组的信息。比如,发送方发送了5个分组,但中间的第三个丢失了,这时接收方只能对前两个分组发出确认,发送方无法知道后面三个分组的下落,只好把后面的三个分组都重发,浪费网络资源。

滑动窗口协议

  • 窗口
    • 允许使用的序列号范围
    • 窗口尺寸为N,最多有N个等待确认的消息
  • 滑动窗口
    • 随着协议的运行,窗口在序列号空间内向前滑动
  • 滑动窗口协议:GBN,SR

Selctive Repeat 协议

  • 接收方对每个分组单独进行确认
    • 设置缓存机制,缓存乱序到达的分组
  • 发送方只重传那些没收到ACK的分组
    • 为每个分组设置定时器
  • 发送方窗口
    • N个连续的序列号
    • 限制已发送未确认的分组

TCP报文段的首部格式

TCP首部的20个字节是固定的,后面4N字节是根据需要而增加的。

TCP首部结构

各个字段:

  • 源端口和目的端口
  • 序号(seq)
    • 范围0-2的32次方-1,序列号增加到最大,下一个序号就返回0。
    • TCP是面向字节流的,在TCP连接中传送的字节流中的每一个字节都按顺序编号,整个要传送的字节流的起始序列号必须在连接建立时设置。首部中的序号字段值指的是本报文段所发送的数据的第一个字节的序号。
    • 例如,一报文段的序号字段值是 301,携带的数据共有100字节。这表明:这个报文段的第一个字节的序号是301,最后一个字节的序号是400,显然,下一段报文段的序号应当从401开始。
  • 确认号(ack)
    • 占4个字节,期望收到对方下一个报文段的第一个数据字节的序号
    • 例如,接收方收到一个报文段,其序号字段值是501,而数据长度是200字节,这表明接收方收到了900为止的数据,所以接收方期望收到的下一个数据序号是701,接收方发送给发送方的确认报文段中把确认号置为701。
    • 记住:若确认号 = N,表明到序号N-1为止的所有数据都已正确收到。
  • 数据偏移
    • TCP首部长度
  • 保留
  • 紧急URG
  • 确认ACK
    • 仅当ACK = 1时,确认号字段才有效,当ACK = 0,确认号无效
    • TCP规定,连接建立后所有传送的报文段都必须把ACK置1
  • 推送PSH
    • 尽快交付,不等到整个缓存填满再发送
  • 复位RST
    • RST = 1,TCP连接出现严重错误,必须释放连接,在重新建立运输连接。
  • 同步SYN
    • 在连接建立时用来同步序号,当SYN = 1 而ACK = 0时,表明这是一个请求报文段。
    • 对方若同意建立,则SYN = 1,ACk = 1,发送响应报文段
    • SYN = 1就表示连接请求或连接接受报文
  • 终止FIN
    • FIN = 1,释放一个连接
  • 窗口
    • 指的是发送报文段的一方的接收窗口,窗口值:允许对方发送的数据量。
    • 因为接收方有缓存空间的限制。
    • 窗口值作为接收方让发送方设置其发送窗口的依据
  • 校验和
    • 检验首部和数据
  • 紧急指针
  • 选项
    • TCP最初只规定了一种选项,最大报文段长度 MSS,MSS是每个TCP报文段中的数据字段的最大长度

TCP可靠传输的实现

以字节为单位的滑动窗口

举例:A收到B发来的确认报文段,其中窗口是20字节,确认号是21(表明B期望的下一个序号是31,30之前的数据已经收到了),下图就是A构造的自己的发送窗口

发送窗口:在没有收到B的确认的情况下,A可以连续把窗口内的数据都发送出去,凡是发送过的数据,在未收到确认之前都必须暂时保留,以便超时重传时使用。

发送窗口的位置由窗口前沿和后沿的位置共同确定。前沿可能向后收缩,发生在对方通知的窗口缩小。

缓存空间和序号空间都是有限的,并且都是循环使用的。

发送缓存用来暂时存放:

  • 发送应用程序传送给发送方TCp准备发送的数据
  • TCP已发送出但尚未收到确认的数据

接收方缓存:

  • 按序到达的,但尚未被应用程序读取的数据
  • 未按序到达的数据

超时重传时间的选择

TCP采用一种自适应的算法,它记录一个报文段发出的时间,以及收到相应的确认的时间,这两个时间之差就是报文段的往返时间RTT。

选择确认SACK

若收到的报文段无差错,只是未按序号,中间缺少一些序号的数据,那么能否只重传未正确达到的数据,选择确认就是一种处理方法。

如果要使用选择确认,在建立连接时,在TCP首部增加”允许SACK“的选项。

TCP的流量控制

利用滑动窗口实现流量控制

流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。

利用滑动窗口机制可以很方便地在TCP连接上实现对发送方的流量控制。在建立连接时,接收方要告诉发送方自己的接收窗口,发送方的发送窗口不能超过接收方给出的接收窗口的数值。

持续计时器(防止非零窗口的通知丢失):只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器,若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅1字节),而对方就在确认这个探测报文段时给出了现在的窗口值,如果窗口仍然为0,那就重置这个持续计时器,如果窗口不是0,那么死锁的僵局就打破了。

考虑传输效率

TCP报文段发送时机的三种机制:

  • TCP维持一个变量,表示当前放入缓存是数据,它等于最大报文段长度MSS时,就组装成一个TCP报文段发出去
  • 由发送方应用进程明确要求发送报文段,即TCP支持的推送操作。
  • 发送方的一个计时器期限到了,就把当前已有的缓存数据装入报文段发出。

TCP拥塞控制

拥塞控制的一般原理

若网络中的许多资源同时呈现供应不足,网络的性能就要明显变坏,整个网络的吞吐量将随输入负荷的增大而下降,这种情况叫做拥塞。

吞吐量:网络中的数据是由一个个数据包组成,防火墙对每个数据包的处理要耗费资源。吞吐量是指在没有帧丢失的情况下,设备能够接受的最大速率。其测试方法是:在测试中以一定速率发送一定数量的帧,并计算待测设备传输的帧,如果发送的帧与接收的帧数量相等,那么就将发送速率提高并重新测试;如果接收帧少于发送帧则降低发送速率重新测试,直至得出最终结果。吞吐量测试结果以比特/秒或字节/秒表示。

拥塞控制就是防止过多的数据注入到网络中,这样就可以使网络中的路由器或链路不止过载。流量控制往往指点对点通信量的控制,是个端到端的问题,流量控制就是要做抑制发送方数据的速率,以便接收到来得及接收。

造成拥塞的原因很复杂:

  • 结点路由器缓存的存储空间太小
  • 处理机处理的速率太慢
  • ...
网络吞吐量与负载的关系

拥塞控制是一个动态的问题,分为开环控制闭环控制两种方法。开环控制方法就是在设置网络事先将有关拥塞的因素考虑周到,力求网络在工作时不产生拥塞。

闭环控制的措施:

  • 检测网络系统以便检测到拥塞在何时何处发生
  • 把拥塞发生的信息传送到可采取行动的地方
  • 调整网络系统的运行以解决出现的问题

几种拥塞控制方法

四种算法:

  • 慢开始
  • 拥塞避免
  • 快重传
  • 快恢复
慢开始和拥塞避免

发送方维持一个拥塞窗口的状态变量,拥塞窗口的大小取决于网络的拥塞程序,并动态变化,发送方让自己的发送窗口等于拥塞窗口。只要网络没出现拥塞,拥塞窗口就再增大一些。

慢开始算法:由小到大逐渐增大发送窗口,通常在刚刚开始发送时,先把拥塞窗口cwnd设置为一个最大报文段MSS,每收到一个确认后,拥塞窗口增加至多一个MSS,每经过一个传输轮次,拥塞窗口cwnd就加倍。发生拥塞(计时器超时还未收到确认)就将拥塞窗口值减到1,再开始慢开始算法。

拥塞避免算法:慢开始之后,进入拥塞避免阶段,拥塞窗口每次增加1,按线性规律慢慢增长。

快重传和快恢复

快重传:要求接收方每收到一个失序的报文段 就立即发出重复确认,尽早重传未确认的报文段

TCP的连接管理

TCP连接过程解决的问题:

  • 要是每一方能够确知对方的存在
  • 要允许双方协商一些参数(最大窗口值等)
  • 能够对运输实体资源进行分配

TCP连接建立

三次握手建立TCP连接

流程:

  • B的TCP服务进程先创建传输控制块TCB,准备接受客户进程的连接请求,服务器进程处于LISTEN状态,等待客户的连接请求
  • A的TCP客户进程也首先创建传输控制模块TCB,向B发出连接请求。首部中的同步位 SYN = 1,同时选择一个初始序号 seq = x。TCP规定,SYN = 1的报文段不能携带数据,但要消耗掉一个序号。TCP客户端进入 SYN-SENT(同步已发送)状态。
  • B收到连接请求报文段后,如同意建立连接,则向A发送确认,在确认报文段中把 SYN 和 ACK(大写)都置为1,确认号ack(小写)= x + 1,同事也为自己选择一个初始序号seq = y。注意,这个报文段也不携带数据,同样消耗一个序号,这时TCP服务器进程进入 SYN-RCVD(同步收到)状态。
  • TCP客户端进程收到B的确认后,还要向B给出确认。确认报文段的ACK = 1,确认号ack = y + 1,自己的序号seq = x + 1。注意:ACK报文段可以携带数据,但如果不携带数据则不消耗序号,这种情况下,下一个数据报文段的序号仍是seq = x + 1。这时TCP连接已建立,A进入ESTABLISHED状态。

说明:A还要发送一次确认,是为了防止已失效的连接请求报文段突然又传送了B,因而产生错误。具体情况:A发出第一个连接请求,但延迟了,A就重发了一个请求,第一个请求延误到连接释放后的某个时间才到达B,这本来是一个失效的连接请求,但B以为是一个新的请求,就会给A一个确认,如果没有第三次握手,那么连接就建立了,会造成资源浪费,有了第三次握手,A并不会理财B的确认,这样连接就不会建立。

TCP连接释放

四次握手TCP连接释放

流程:

  • 数据传输结束后,通信的双方都可释放连接。
  • A和B都处于ESTABLISHED状态,A的应用进程先向其TCP发出连接释放报文段,并停止再发送数据,主动关闭TCP。A把连接释放报文段 FIN 置1,其序号seq = u,它等于前面已传送过的数据的最后一个字节的序号加1,这时A进入FIN-WAIT-1(终止等待1)状态,等待B的确认。注意:TCP规定,FIN报文段即使不携带数据,也消耗一个序号。
  • B收到连接释放报文段后,即发出确认,确认号ack = u+1,自己的序号seq = v,等于B前面已传送过的数据的最后一个字节的序号加1,B就进入 CLOSE-WAIT(关闭等待)状态。TCP服务器进程这时通知高层应用进程,从A到B这个方向的连接就释放了。这时TCP处于半关闭状态,即A已经没有数据要发送,但B发送数据,A还能接收。
  • A收到来自B的确认后,就进入FIN-WAIT-2(终止等待2)状态,等待B发出的连接释放报文段。
  • 若B已经没有要向A发送的数据,就发出连接释放报文段,FIN = 1,B进入(LAST-ACK)状态,等待A确认
  • A发送确认报文段,ACK = 1,进入TIME-WAIT状态,这时TCP还没有释放掉,必须经过时间等待计时器设置的时间后,A才能进入CLOSE状态。

TCP的有限状态机

TCP有限状态机
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容