IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 计算机网络读书笔记(三) -> 正文阅读

[网络协议]计算机网络读书笔记(三)

运输层

传输层位与应用层和网络层之间,是分层的网络体系结构的重要部分。该层为运行在不同主机上的应用进程提供直接的通信服务起着至关重要的作用。

一. 概述和运输层服务

运输层协议为运行在不同主机上的应用程序之间提供了逻辑通信功能。从应用程序的角度看,通过逻辑通信,运行不同进程的主机好像直接相连一样,实际上,这些主机是通过很多路由器及不同类型的链路相连,也就是说,对于运输层而言,他起到的作用是进程与进程之间的通信

在发送端,运输层将从发送应用程序进程接收到的报文转化成运输层分组,该分组称为运输层报文段。实现的方法可能是将应用报文划分为较小的块,并为每块加上一个运输层首部以生成运输层报文段。然后在发送端系统中,运输层将这些报文段传递给网络层,网络层将其封装成网络层分组(即数据报)并向目的地发送。网络路由器仅将其作用于该数据报的网络层字段,即他们不检查封装在该数据报的运输层报文段的字段。在接收端,网络层从数据报中提取运输层报文段,并为该报文段向上交给运输层。运输层则处理接收到的报文段,使该报文段中的数据为接收应用进程使用。

网络应用可以使用多种传输层协议,因特网有两种传输层协议,即TCPUDP,不同的传输层协议提供不同的运输层服务。

1.1.1 运输层和网络层的关系

在协议栈中,运输层刚好为于网络层之上。网络层提供了主机之间的逻辑通信,而运输层为运行在不同主机上的进程之间提供了逻辑通信。

运输层协议只工作在端系统中。在端系统中,传输层协议将来自应用进程的报文移动到网络边缘即网络层,反过来也从网络层接收这些报文段;传输层对报文段如何在网络核心传输并不做干涉;事实上中间路由器既不处理也不识别传输层加载应用层报文上的任何信息

运输层协议能提供的服务常常受制于底层网络层协议的服务类型,如果网络层协议无法为主机之间的通信提供时延和带宽保证的话,运输层协议也就无法为进程之间发送的应用程序报文提供时延或者带宽保证.

然而即使底层网络协议不能在网络层提供响应的服务,运输层协议也能提供某些服务。例如,即使底层网络协议是不可靠的,运输协议也能为应用程序提供可抗的数据传输服务。

1.1.2 因特网运输层概述

因特网为应用层提供了两种截然不同的可用传输层协议。这些协议一种是UDP(用户数据报协议),它为调用它的应用程序提供了一种不可靠、无连接的服务。另一种是TCP(传输控制协议),它为调用它的应用程序提供了一种可靠的、面向连接的服务。

因特网网络层协议有一个名字叫IP协议,即网际协议。IP为主机之间提供了逻辑通信。IP的服务模型是尽力而为交付服务。这意味这IP尽它最大努力在通信的主机之间交付报文段,但他不并不做任何确保。它不确保报文段的交付,不保证报文段的按序交付,不保证报文段中数据的完整性,由此,IP被称为不可靠服务

UDP和TCP的最基本的责任是,将两个端系统间IP的交付服务扩展为运行在端系统上的两个进程之间的交付服务。将主机间交付扩展到进程间交付被称为运输层的多路复用多路分解。UDP和TCP还可以通过在其报文段首部中包括差错检查字段而提供完整性检查。进程到进程的数据交付和差错检查是两种最低限度的运输层服务,也是UDP所能提供的仅有的两种服务。UDP也是一种不可靠的服务

TCP为应用程序提供了几种附加服务。首先,它提供可靠数据传输。通过流量控制、序号、确认和定时器,TCP确保正确地,按序地将数据从发送进程交付给接收进程,这样,TCP就将两个端系统之间的不可靠IP服务转化成一种进程间的可靠数据传输服务。TCP还提供拥塞控制,可以防止任何一条TCP连接用过多流量来淹没通信主机之间的链路和交换设备。

二. 多路复用与多路分解

有前面的介绍,我们可以知道,传输层将网络层提供的面向主机的逻辑通信扩充为面向不同应用进程的逻辑通信,并且这一过程称为多路复用和多路分解;值得注意的是,多路复用和多路分解是每个计算机网络都需要的。

在目的主机,运输层从紧邻其下的网络层接收报文段。运输层负责将这些报文段中的数据交付给主机上运行的适当应用程序进程。一个进程有一个或多个套接字,它相当于从网络向进程传递数据和从进程向网路传递数据的门户。因此,在接收主机中的运输层实际上并没有直接将数据交付给进程,而是将数据交付给了中间的一个套接字。由于每个套接字都有唯一的标识符(此标识符称为端口号,端口号大小在0-65535之间,其中0-1023属于周知端口号,它们为特定的Socket而拥有),标识符的格式决定它是UDP还是TCP套接字,因此由此可以区分是交付给哪个进程。

传输层从同一台主机上的不同Socket接收数据的过程称为多路复用;传输层向同一台主机上的不同Socket传输数据的过程称为多路分解;为了实现多路复用和多路分解,我们需要标志套接字,并将相关信息添加到报文段中。

在发送方主机多路复用:
从多个套接字接收来自多个进程的报文,根据套接字对应的IP地址和端口号等信息对报文段用头部加以封装(该头部信息用于之后的解复用)。
在接收方主机多路解复用:
根据报文段的头部信息中的IP地址和端口号,将接收到的报文段发送给正确的套接字。

  1. 无连接的多路复用与多路分解
    一个UDP套接字是由一个二元组全面标识的,该二元组包含一个目的IP地址和一个目的端口号。因此,如果两个UDP报文段有不同的源IP地址和/或源端口号,但具有相同的目的IP地址和目的端口号,那么这两个报文段将通过相同的目的套接字被定向到相同的目的进程

  2. 面向连接的多路复用与多路分解
    TCP套接字是由一个四元组(源IP地址,源端口号,目的IP地址,目的端口号)来标识的。因此,当一个TCP报文段从网路到达一台主机时,该主机使用全部4个值来将报文段定向(分解)到相应的套接字。特别与UDP不同的是,两个具有不同源IP地址或源端口号的到达TCP报文段将被定向到两个不同的套接字,除非TCP报文段携带了初始创建连接的请求

    在TCP中,存在一个欢迎套接字,他在某一个端口上等待TCP客户端的连接请求,假如接收到一个连接请求后,对应的服务器进程就会创建一个新的套接字

    当一个TCP报文段到达主机时,所有四个字段被用来将报文段定向(分解)到相应的套接字。

三.无连接运输:UDP

UDP从应用程序得到数据,附加上用于多路复用/分解服务的源和目的端口号字段,以及两个其他的小字段,然后将形成的报文段交给网络层。网络层将该运输层报文段封装到一个IP数据报中,然后尽力而为地尝试将此报文段交付给接收主机。如果报文段到达接收主机,UDP使用目的地端口号将报文段中的数据交付给正确的应用进程。在使用UDP时,在发送报文段之前,发送方和接收方的运输层实体之间没有握手,因此,UDP被称为是无连接的。

既然TCP提供了可靠数据传输,并且提供了拥塞控制,为什么人们还需UDP呢?事实上,有些应用很适合UDP(因为没有连接过程,不会受拥塞控制的调节);UDP有以下好处:

  • 关于何时、发送什么数据的应用层控制更为精细:这是因为一旦应用程序将数据交给UDP,UDP就会打包将其发送给网络层,不会受到传输层的调节,这在一些实时应用中比较实用;当然,应用程序还可以通过UDP+自主开发一些功能的模式来扩展UDP。
  • 无需建立连接:所以就不会引入额外的时延。这也可能是DNS使用UDP而不是TCP的主要原因,如果使用TCP的话,DNS服务将会慢很多;HTTP使用TCP的主要原因是对TCP的可靠性的依赖超过对速度的要求;
  • 无需维护连接状态:TCP为了实现可靠数据传输和拥塞控制需要在端系统中维护一些参数,这些参数包括:接收和发送的缓存、拥塞控制参数、确认号和序号;这些参数信息都是必须的;而UDP因为不建立连接,所以自然也就不需要维护这些状态,这就减少了时空开销;
  • 分组首部更小:TCP有20字节的首部开销,而UDP只有8字节;

这些应用程序使用了TCP作为其传输层协议:电子邮件、远程终端访问、Web、文件传输;这些应用通常使用UDP作为其传输层协议:远程文件服务器、网络管理(因为这里应用即便在网络处于拥塞的情况下仍要工作,所以UDP更为合适)、路由选择协议和名称转换(DNS);这些应用两个都有使用:流式多媒体、因特网电话等多媒体应用;这些应用对实时性的要求较高同时对可靠性的要求又不是很高,所以既可以使用UDP也可以使用TCP协议。

不过在UDP之上运行多媒体应用是有争议的,因为UDP没有拥塞控制协议,所以其对网络有很大的威胁性:大量的UDP流量将使网络过度拥塞而造成TCP连接几乎无法传输数据,并且因为网络拥塞,所以应用又有着较高的丢包率,而因为丢包率UDP很有可能继续发送数据,由此使得网络效率低下。也有研究人员提出一些新的机制,使得所有数据源,包括UDP源执行自适应的拥塞控制来解决这一问题;

需要注意的是,使用UDP仍然可以实现可靠数据传输,只不过这一部分功能需要在应用程序中自主开发;将可靠性直接构建于应用程序中。将使其既可以可靠地传输数据又可以避免受制于TCP的拥塞控制(传输速率的控制)

3.1 UDP报文段结构

在这里插入图片描述
UDP首部只有4个字段(源端口号、目的端口号、长度、校验和),每个字段由两个字节组成。通过端口号可以使目的主机将应用数据交给运行在目的端系统中的相应进程。长度字段指示了在UDP报文段中的字节数(首部加数据)。因为数据字段的长度在一个UDP段中不同于在另一个段中,因此需要有一个明确的长度。接收方使用检验和来检查在该报文段中是否出现了差错。

3.2 UDP校验和

UDP检验和提供了差错检测功能。校验和用于确定当UDP报文段从源到达目的地移动时,其中的比特是否发生了改变。发送方的UDP对报文段中的所有16比特字的和进行反码运算,求和时遇到的任何移除都被回卷(将进位加到最低位)。

发送方:
①将报文段的内容视为16比特的整数
②校验和:报文段的加法和(1的补运算)
③发送方将校验和放在UDP的检验和字段
接收方:
①计算接收到的报文段的校验和
②检查计算出的校验和与校验和字段的内容是否相等,不等一定有错,相等可能有错。

UDP作为传输层协议,提供的差错检测功能很有可能和底层协议提供的相似功能产生冗余;但是,这是必须的,因为由于不能保证源和目的地之间所有链路都提供差错检测功能,即便数据在链路上正确传输,也无法保证其在中间路由器的内存中不发生错误;所以要实现端到端的差错检测,就必须在传输层协议中实现该功能;这一原则在系统设计中被称为端到端原则:“因为某一功能必须在端到端实现,与在较高层次提供这些功能的代价相比,在较低层次上设置的功能可能是冗余的,或者根本是没有用的”。IP作为网络层协议,可以运行在任何第二层协议上,所以运输层提供差错检测也是必须的;UDP可以检测差错,但是无法恢复差错,能做的除了将其丢弃外,便是将其交给应用程序然后给出警告。

四.可靠数据传输原理

可靠数据传输为上层提供的服务抽象是:数据可以通过一条可靠的信道进行传输。借助于可靠信道,传输数据比特就不会收到损坏或丢失,而且所有数据都是按照其发送顺序进行交付。实现这种服务抽象是可靠数据传输协议的责任。
在可靠的数据传输下,我们将:

  1. 渐增式地开发可靠数据协议的发送方和接收方
  2. 只考虑单向数据传输,双向的数据传输问题实际上是两个单向数据传输问题的综合
  3. 使用有限状态机(FSM)来描述发送方和接收方。

4.1 经完全可靠信道的可靠数据传输: rdt1.0

首先我们假设底层信道是完全可靠的,即分组在底层信道传输时,没有比特出错,没有分组丢失;发送方的数据将数据送到下层信道,接收方从下层信道接收数据。
在这里插入图片描述

因为有了完全可靠的信道,因此无需考虑出现差错,此时就不需要任何回馈信息。

4.2.经具有比特差错信道的可靠数据传输:rdt2.x

rdt2.0:
底层信道更为实际的模型是分组中的比特可能受损的模型。在实际生活中,我们在交流时,通常会要求对方在得到信息后发出一个肯定确认否定确认。这些确认可以让发送方知道接收方知道哪些内容被正确洗手,哪些内容接收有误并需要重复发送。在计算机网络环境中,基于这样的重传机制的可靠数据传输协议称为自动重传请求协议(ARQ)

ARQ协议还需要另外三种协议功能来处理存在比特差错的情况:
①. 差错检测:首先,需要一种机制以使接收方检测到何时出现了比特差错。这时需要有额外的比特从发送发发送到接收方,这些比特将被汇集在rdt2.0数据分组的分组检验和字段中。
② . 接收方反馈:发送方想要了解接收方是否正确接收分组,唯一的途径就是让接收方提供明确的反馈信息给发送方。即肯定确认(ACK)否定确认(NAK)。这些分组理论上仅仅需要一个比特长,用0表示NAK,用1表示ACK。
③. 重传:接收方收到有差错的分组时,发送方将重传该分组文。

在这里插入图片描述
注:当发送方处于等待ACK或NAK的状态时,它不能从上层获得更多的数据,也就是说rdt_send()事件不可能出现;仅当接收到ACK并离开该状态时才能发生这样的事件。因此,发送发将不会发送一块新数据,除非发送方确信接受方已正确接收当前分组,因此,rdt2.0协议又被称为停等协议

rdt2.1:
但是此时还有一个致命的问题,假如我们的ACK或NAK分组受损该怎么处理!
处理ACK或NAK受损时的三种情况:
①.无法识别对方返回的确认信息,即无法分别返回的是ACK或NAK中的哪一种,此时,发送方将复述其回答,然后发送至接收方,但是中途可能还会出现错误,因此此方法十分困难。
②.增加足够的检验和比特,使得发送方不仅可以检测差错,还可以回复差错,对于会产生差错但是不丢失分组的信道,这就可以直接解决问题。
③.当收到含糊不清的ACK或者NAK时,只需要重传当前数据分组即可,然后这种方法在发送发到接收方的信道中引入了冗余分组。但是 因为冗余分组的存在,接收方不知道它所发送的ACK或NAK是否被发送方正确收到。

解决此问题的一个简单办法,就是在数据分组中添加一个信字段,让发送方对其数据分组编号,即将发送数据分组的序号放在该字段,此时,接收方只需要检查序号即可确定收到的分组是否一次重传。
rdt2.1
rdt2.2:
当接收到失序的分组时候,接收方对所接收的分组发送一个肯定确认。如果收到受损的分组,则接收方将发送一个否定确认。如果不发送NAK,而是对上次正确接收的分组发送一个ACK,我们也能实现与NAK一样的效果(很好理解,比如说你给我依次发送两个,当发送完第二个报文后,我对你说你的第一个报文发送完毕了,那不就意思是你的第二个报文有问题要重新发送嘛)。发送方接收到对同一个分组的两个ACK(即接收冗余ACK)后,就知道接收方没有正确收到跟在被确认两次的分组后面的分组。

rdt2.2是在有比特差错信道上实现的一个无NAK的可靠数据传输协议。rdt2.1和rdt2.2之间的变化在于:接收方此时必须包括由一个ACK报文所确认的分组序号(这可以通过在接收方FSM中,在make_pkt()中包括参数ACK 0或ACK 1来实现),发送方此时必须检查接收到的ACK报文中被确认的分组序号

在这里插入图片描述
在这里插入图片描述

4.3 经具有比特差错的丢包信道的可靠数据传输:rdt3.0

现在假定除了比特受损外,还存在底层信道会丢包,协议此时就需要关注:怎样检测丢包以及丢包后该怎么办。在之前的rdt2.x中我们通过校验和、序号、ACK分组和重传机制等来解决第二个问题,对于第一个问题,我们使用如下方法。

我们假设发送方传输了一个数据分组,该分组或者接收方对该分组的ACK发生了丢失,那么此时发送方都收不到应当到来的接收方的响应,如果发送发愿意等待足够长的时间以便确认分组丢失,那么它只需要重传该数据分组即可,下面我们要做的就是确认等待时间。

我们认为,发送方至少等待这样长的时间:即发送方与接收方之间的一个往返时延加上接收方处理一个分组所需要的时间。如果在这个时间内没有收到ACK请求,就重传该分组(超时重传机制).但是也有可能分组经历了一个特别大的时延,发送发可能会重传该分组,即使该分组及ACK都没有丢失,那么就会引入冗余数据分组,我们此时可以通过rdt2.2中的序号来处理冗余分组情况。为了实现基于时间的重传机制,需要一个倒计数定时器,在一个给定的时间量过期后,可中断发送方

因为分组序号在0和1之间交替,因此rdt3.0有时被称为比特交替协议
在这里插入图片描述

4.4 流水线可靠数据传输

rdt3.0虽然功能正确,但是在高速网络下性能太低,因为他是一个停等协议
解决性能问题最直接的方法:不以停等方式运行,允许发送方发送多个分组而无需等待确认。因为许多从发送方向接收接受方输送的分组可以被看成是填充到一条流水线,故这种技术被称为流水线

要使用流水线模式,必须满足下面条件:

  • 必须增加序号范围,因为每个输送中的分组(不计算重传的)必须有一个唯一的序号,而且也许有多个在输送中的未确认报文
  • 协议的发送方和接收方两端也要能缓存多个分组。发送方最低限度应当能够缓冲哪些已发送但没有确认的分组;接收方需要能缓存哪些已正确接收的分组
  • 所需要的序号范围和对缓冲的要求取决于数据传输协议如何处理丢失、损坏及延时过大的分组

解决流水线的差错恢复有两种基本的方法是:回退N步选择重传
在这里插入图片描述

4.5 回退N步

在回退N步(GBN)协议中,允许发送方发送多个分组(当有多个分组可用时)而不需要等待确认,但是它也受限于在流水线中未确认的分组数不能超过最大允许数N。
在回退N步中,发送方维护一个N大小的窗口和一个base,发送方期待收到的最小待确认分组序号,同样也是窗口的起点,还有一个next Sequence变量,表示上层需要发送分组时,可以使用的序号。这样全部序号就被划分为0-base-1,这一部分的分组是已发送且收到接收方确认的分组,base~next Sequence-1这一部分的分组是已发送但是尚未收到确认的,其中base是尚未收到确认的最小序号;next-1~base+N-1表示当前发送方可以使用的序号,表示一种发送能力;当发送方收到确认号为base的确认分组后就会向前移动窗口,所以回退N步也被称为滑动窗口协议
在这里插入图片描述
滑动窗口协议:发送窗口
发送缓冲区:

  • 形式:内存中的一个区域,落入缓冲区的分组可以发送
  • 功能:已发送但是还没有得到确认的分组
  • 必要性:需要重发时可用

发送缓冲区的大小:

  • 停止等待协议=1
  • 流水线协议>1,选择合理的值不能很大,链路利用率不能超过100%

发送缓冲区的分组:

  • 未发送的:落入发送缓冲区的分组,可以连续发送出去
  • 已经发送的:等待对方确认的分组,只有得到了确认才能删除

发送窗口:

  • 发送缓冲区的一个范围,哪些已经发送但未经确认的序号构成的空间
  • 发送窗口的值<=发送缓冲区的值
  • 一开始没有发送任何一个分组,后沿=前沿;每发送一个窗口前沿前移一个单位。

这是发送方需要维护的数据,同时发送方需要响应的事件有:上层调用收到ACK超时事件

  • 上层调用:检查next Sequence是否在窗口之内,如果在,这说明发送方还有发送能力,发送之;
  • 收到ACK:回退N步策略对序号为n的分组采取累积确认的方式,即当收到序号为n的ACK时,表明序号小于等于n的分组全部到位;发送方收到的ACK毕竟来自接收方,收到ACK的情况还得看接收方如何发送;
  • 超时事件:如果发生超时事件,那么发送方会重发所有已发送但是未确认的分组,即分组号在base和next sequence-1之间的所有分组;这也是为什么叫“回退N步”,如果收到一个ACK,则定时器会重行启动;如果没有待确认的分组,定时器将被终止;

滑动窗口协议:接收窗口

  • 接收窗口用于控制哪些分组可以接收
    只有收到的分组序号落入接收窗口内才允许接收;
    若序号在接收窗口之外,则丢弃
    若接收到的分组序号与之前所接收到的分组序号乱序(比如说已经接收到1号分组,此时又传来3号分组),那么就将新接受的分组丢弃。
  • 接收窗口尺寸Wr=1,则只能顺序接收
  • 接收窗口尺寸Wr>1,则可以乱序接收,但提交给上层的分组需要按序

两个窗口的互动:
发送窗口:

  • 有了新的分组落入发送缓冲区范围内,发送并前沿滑动
  • 来了老的低序号分组的确认后,后沿向前滑动,新的分组可以落入发送缓冲区的范围内

接收窗口:

  • 收到分组,落入到接收窗口范围内,接收
  • 是低序号,发送确认给对方

在这里插入图片描述

4.6 选择重传(SR)

回退N步协议存在一个问题就是当窗口和带宽的时延都较大时,单个分组的差错可能会引起GBN重传大量的分组,然后许多本来不用重传的分组会充斥在信道中,造成资源浪费;选择重传就是让发送方仅重传那些丢失和受损的分组而避免不必要的重传。

顾名思义,选择重传(SR)协议通过让发送方仅重传那些它怀疑在接收方出错(即丢失或受损)的分组而避免了不必要的重传
在这里插入图片描述
SR接收方将确认一个正确接收的分组而不管其是否按需排序。时许的分组将被缓存直到所有丢失分组(即序号更小的分组)皆被收到为止,这样才可以将一批分组交付给上层

SR 发送方的事件和动作

  • 从上层接收数据: 检查下一个可用于该分组的序号,若在发送方的窗口内,则将数据打包发送。
  • 超时: 定时器再次用来防止丢失分组。但是现在每个分组必须得有单独的定时器。
  • 收到 ACK:倘若该分组序号在窗口内,则 SR 发送方将那个被确认的分组标记为已接收。如果该分组的序号等于send_base,则窗口基序号向前移动到具有最小序号的未确认分组处。如果窗口移动了并且该序号落在窗口内的未发送分组,则发送这些分组。

SR 接收方的事件和动作:

  • 序号在 [rcv_base, rcv_base + N -1] 内的分组被正确接收:在此情况下,收到的分组落在接收方的窗口内,一个选择 ACK 被回送给发送方。如果该分组以前没收到过,则缓存该分组。如果该分组的序号等于接收窗口的基序号,则该分组及以前缓存的序号连续的分组交付给上层。
  • 序号在 [rcv_base - N, rcv_base - 1] 内的分组被正确接收: 产生一个 ACK,即使该分组是接收方以前已确认过的分组。因为视图不一致
  • 其他情况:忽略该分组。

接收方将确认一个正确接收的分组而不管其是否按序;失序的分组被缓存,直到形成连续数据后将其提交给上层;值得注意的是,如果接收方收到了已经确认的分组,则说明确认ACK丢失,或者时延太长,接收方和发送方沟通不及时;这也表明了关于那些分组到位了,那些分组还没到位,接收方和发送方有着不一样的视图。

另外还需要注意的是,序号的重用问题,如果在分组中序号字段的位数为k,那么最大的序号为2^k-1,所以有可能不同分组同时占用一个序号,为了避免这种情况,需要做的是控制分组的生命周期。窗口长度必须小于或等于序号空间大小的一半。
在这里插入图片描述
通过上图的对比可以看出:对于SR协议来讲,其与滑动窗口协议不同的地方在于,如果发送的分组没有收到ACK确认,那么超时后就会重新发送当前分组而不是全部重新发送;对于接收端而言,吐过收到的分组序号乱序,也不会直接丢弃而是缓存起来,等到之前丢失的分组收到后,再按序加之前缓存好的分组直接交付给上层,因此说SR是滑动窗口协议的一个改进。

可靠数据传输机制以及用途的总结:

在这里插入图片描述

五.面向连接的传输:TCP

TCP是因特网运输层的面向连接的可靠的运输协议。为了提供可靠数据传输,TCP依赖于前一节所讨论的许多基本原理,其中包括差错检测,重传,累计确认,定时器以及用于序号和确认号的首部字段

5.1 TCP连接

TCP被成为是面向连接的,这是因为在一个应用进程可以开始向另一个应用进程发送数据之前,这两个进程必须先相互握手,即它们必须相互发送某些预备报文段,以确保数据传输的参数

TCP连接是一条逻辑连接,其共同状态仅保留在两个通信端系统的TCP程序中。中间路由器对TCP连接完全视而不见,它们看到的是数据报而不是连接。TCP提供的是全双工服务,并且是点对点的。

三次握手的过程:客户首先发送一个特殊的TCP报文段,服务器用另一个特殊的TCP报文段来响应,最后客户再用第三个特殊报文段作为响应。前两个报文段不承载“有效载荷”,也就是不包含应用层数据;而第三个报文段可以承接有效载荷,由于两台主机之间发送了3个报文段,所以这种连接建立过程常被称为三次握手

当TCP连接建立后,两个应用进程就可以发送数据了。应用程序将要发送的数据通过Socket传递给TCP,TCP将数据引导到该连接的发送缓存,发送缓存大小是在三次握手的过程中确定的;之后TCP将时不时从该缓存中拿出数据进行发送,一个有趣的事情是,TCP规范中没有规定TCP应该在何时发送缓存里的数据,描述为“TCP应该在它方便的时候以报文段的形式发送数据”;TCP每次可以从缓存中发送的最大数据长度称为MSS(Maximum Segment Size)。一般来说,MSS+TCP/IP首部的长度要小于等于链路的MTU(即链路层最大帧长度Maximum Transport Unit)而以太网和PPP的MTU都等于1500字节,TCP/IP的首部通常为40字节,所以MSS一般来说为1460字节

注意:MSS指的是报文段中应用层数据最大长度,而不是包括TCP首部的报文段长度。

TCP为每块客户数据加上TCP首部后就形成了一个个TCP报文段;这些TCP报文段被交给网络层,然后被发送到网络中;当TCP报文段到达接收端时,便进入了接收端的缓存,等待被应用程序读取。

TCP连接的每一端都有发送和接收缓存。

5.2 TCP报文段结构

TCP首部包括源端口号和目的端口号,它被用于多路复用/分解来自或送到上层应用的数据,另外,同UDP一样,TCP首部也包括检验和字段,TCP报文段首部还包含下列字段:

  • 32比特的序号字段和32比特的确认号字段,这些字段被TCP发送方和接收方用来实现可靠数据传输服务。
  • 16比特的接收窗口字段,这字段用于流量控制
  • 4比特的首部长字段,该字段指示了以32比特的字为单位的TCP首部长度。
  • 可选与变长的选项字段,该字段用于发送方与接收方协商最大报文段长度MSS时,或在高速网络环境下用作窗口调教因子使用。
  • 6比特的标志字段。ACK比特用于只是确认字段中的值是有效地,即该报文段包括一个对已被成功接收报文段的确认。RST,SYN,FIN比特用于连接建立和拆除。
    在这里插入图片描述
    1.序号和确认号
    TCP把数据看成一个无结构的有序的字节流。一个报文段的序号是该报文段首字节的字节流编号。因为TCP是全双工的,因此主机A在向主机B发送数据的同时,也许也接收来自主机B的数据(都是同一条TCP连接的一部分)。从主机B到达的每个报文段中都有一个序号用于从B流向A的数据。主机A填充进报文段的确认号是主机A期望从主机B收到的下一个字节的序号。再举一个例子,假设主机A已收到一个来自主机B的包含字节0~535的报文段,以及另一个包含900-1000的报文段。主机A为了重新构建主机B的数据流,仍在等待字节536(和其后的字节)。因此,A到B的下一个报文段将在确认号字段中包含536.因此TCP只确认该流中至第一个丢失字节为止的字节,所以TCP被称为累计确认

5.3 往返时间的估计和超时

TCP如同之前所讲的rdt协议一样,采用超时/重传机制来处理报文段的丢失问题。超时时间一定大于该连接的往返时间(RTT),但是该如何设置呢?

TCP使用一种Sample RTT的方法来估计RTT。Sample RTT就是从某报文段发出到收到对该报文段的确认之间的时间量。大多数TCP的实现是在某个时刻做一个Sample RTT测试。TCP并不为已经重发的报文段做Sample RTT测试,它只为传输一次的报文段测量Sample RTT。

TCP一般来说通过Estimated RTT=(1-a)Estimated RTT+a*Sample RTT来计算因路由器的拥塞和端系统负载变化所导致变化的RTT。a一般取1/8;因为Estimated RTT表示最近的网络状况,所以其理应得到较大的权值;这种方法也被称为指数加权移动平均

除了估计RTT外,计算RTT的变化也是ok的,DevRTT =(1-b)DevRTT+b*|Sample RTT-Estimated RTT|;其中b的推荐值为0.25;当Sample RTT变化较大的时候,DevRTT的值较大,当Sample RTT变化较小的时候,DevRTT就较小;

TCP是如何考虑超时时间的呢?该时间因略大于测量的RTT,不易过小——容易引起不必要的重传,也不易过大——网络对于报文段丢失情况的反应就会变慢;最后TCP采用了如下计算方式:Timeout Interval=Estimated RTT+4*Dev RTT;

当出现超时后,TimeOutInteval值将加倍。不管怎么样,一旦报文段收到并更新Estimated RTT后,TimeInteval就又用上值计算了。

5.4 可靠数据传输

TCP在IP不可靠的尽力而为服务之上创建了一种可靠数据传输服务。TCP的可靠数据传输服务确保一个进程从其接收缓存中读出的数据流是无损坏、无间隙、非冗余和按序的数据流,即该字节流与连接的另一方端系统发送出的字节流是完全相同的。
TCP的发送方有3个与发送和重传有关的主要事件:从上层应用接收数据,定时器超时和收到ACK。
在这里插入图片描述
1.一些有趣的情况
以下展示三种不同情况下简易版本的TCP连接:
在这里插入图片描述
注意:在下面这种情况下,主机A的第一个报文段的确认报文在网络中丢失,但是在超时事件发生之前主机A收到一个确认号为120的确认报文。主机A因此知道了主机B已经收到了序号为119及之前的所有字节,所以主机A不会重传这两个报文段中的任何一个

在这里插入图片描述
2.超时间隔加倍
每当超时事件发生时,TCP重传具有最小序号的还未被确认的报文段。只是每次TCP重传时都会将下一次的超时间间隔设为先前的两倍。因此,超时间间隔在每次重传后会呈指数型增长,然而,当定时器在另两个事件(即收到上层应用的数据和收到ACK)中的任意一个启动时,TimeoutInterval由最近的EstimatiedRTT值与DevRTT值推算得到。这种办法是一个形式受限的拥塞控制。

3. 快速重传
超时触发重传存在的问题之一是超时周期可能相对较长,当一个报文段丢失时,这种长超时周期迫使发送方延迟重传丢失的分组,因而增加了端到端的时延。发送方可以在超时事件发生之前通过注意所谓冗余ACK来较好地检测到丢包情况冗余ACK就是再次确认某个报文段的ACK,而发送方先前已经收到对该报文段的确认。要知道接收方为什么要发送冗余ACK,可以先看下表关于产生TCP ACK的建议:
在这里插入图片描述
因为发送方经常一个接一个地发送大量的报文段,如果一个报文段丢失,就可能引起许多一个接一个的冗余ACK。如果TCP发送方接收到对相同数据的3个冗余ACK,说明这个已被确认过3次的报文段之后的报文段已经丢失,那么就执行快速重传,即在该报文段的定时器过期之前重传丢失的报文段

为什么是3个冗余ACK:
是因为当接收到第一个ACK代表的是正常,收到第二个ACK代表接收方乱序,可能是由于网络时延等原因导致,当收到第三个ACK的时候则表示该分组已经很大可能丢失了。
在这里插入图片描述

4. 是回退N步还是选择重传
TCP确认是累计式的,正确接收但失序的报文段是不会被接收方逐个确认的。因此,**TCP发送方仅需维持已发送过但未被确认的字节的最小序号和下一个要发送的字节的序号。**看上去像是GBN风格的协议,但是还是有一些区别。

对TCP提出的一种修改意见是所谓的选择确认,它允许TCP接收方有选择的确认失序报文段,而不是累计地确认最后一个正确接收的有序报文段。当该机制与选择重传机制结合起来使用时,TCP就很像SR协议了,因此,TCP应该是二者的混合。

5.5 流量控制

当TCP连接接收到正确、按序的字节后,它就将数据放入接收缓存。但是,接收方应用也许忙于其他工作,甚至要过很长事件后才去读取数据,因此,此时如果发送发发送太多太快,发送的数据就会很容易使该链接的接收缓存溢出

TCP为它的应用程序提供了流量控制服务以消除接收方缓存溢出的可能性,流量控制服务因此是一个速度匹配服务,即发送方的发送速率与接收方的应用读取速读像匹配。

TCP通过让发送方维护一个称为接收窗口的变量来提供流量控制。通俗地说,接收窗口用于给发送方一个指示-该接收方还有多少可用的缓存空间。因为TCP是全双工通信,因此连接的两端都各自维护一个接收窗口。

在TCP首部中有一个窗口大小字段,TCP连接的双方通过该字段来向对方表明自己的窗口大小,即缓存空间的大小;同样,在TCP连接的两端,各自维护着相关的变量:last Sentlast Acked;在发送方,这两个变量之间的分组就是已经发送但是尚未确认的分组;而在接收方,last Read表示应用进程下一次读取的数据,last Revd表示最后纳入缓存的报文段编号(注意,我们讨论的前提是TCP会将失序到达的报文段丢弃);通过这些变量以及报文段首部中窗口大小字段,我们就可以对发送速度做一些控制:在发送方last Sent-last Acked应该小于等于接收方的窗口大小;在接收端A=last Received-last Read就是已经使用的空间大小,所以窗口大小=buffer-A;

还有一个问题就是,如果接收方的窗口大小为0,那么发送端该如何处理呢?一个需要注意的事实是,接收方在没有ACK或者数据要向发送端发送的时候,是不会通知发送方其窗口大小已经改变,即如果应用程序读取了缓存中的数据,发送方是不会知道的,除非它向接收方发送了数据,而发送方对其进行了确认;实际上,发送方也是这么做的!当接收到窗口大小为0的报文段后,发送方会向接收方间隔发送只有一个字节的数据

5.6 TCP连接管理

1.TCP三次握手

TCP协议中,主动发起请求的一端称为『客户端』,被动连接的一端称为『服务端』。不管是客户端还是服务端,TCP连接建立完后都能发送和接收数据。

起初,服务器和客户端都为CLOSED状态。在通信开始前,双方都得创建各自的传输控制块(TCB)。服务器创建完TCB后遍进入LISTEN状态,此时准备接收客户端发来的连接请求。

第一次握手
客户端TCP向服务端TCP发送一个特殊的报文段。该报文段不包含应用层数据,但是其首部中SYN=1,ACK=0,seq=x,其中x是客户随机选择一个初始序号,并将此序号放置于该起始的TCP SYN报文段的序号字段部分。请求发送后,客户端便进入SYN-SENT状态。

PS1:SYN=1,ACK=0表示该报文段为连接请求报文。
PS2:x为本次TCP通信的字节流的初始序号,是客户随机分配的。
TCP规定:SYN=1的报文段不能有数据部分,但要消耗掉一个序号。

第二次握手
服务端收到连接请求报文段后,如果同意连接,则会发送一个应答:SYN=1,ACK=1,seq=y,确认号=x+1
该应答发送完成后便进入SYN-RCVD状态。

PS1:SYN=1,ACK=1表示该报文段为连接同意的应答报文。
PS2:seq=y表示服务端作为发送者时,发送字节流的初始序号。
PS3:确认号=x+1表示服务端希望下一个数据报发送序号从x+1开始的字节。

第三次握手
当客户端收到连接同意的应答后,还要向服务端发送一个确认报文段,表示:服务端发来的连接同意应答已经成功收到。
该报文段的头部为:ACK=1,seq=x+1,确认号=y+1。
客户端发完这个报文段后便进入ESTABLISHED状态,服务端收到这个应答后也进入ESTABLISHED状态,此时连接的建立完成,此时SYN比特被置为0!

为什么连接建立需要三次握手,而不是两次握手?
防止失效的连接请求报文段被服务端接收,从而产生错误。
失效的连接请求:若客户端向服务端发送的连接请求丢失,客户端等待应答超时后就会再次发送连接请求,此时,上一个连接请求就是『失效的』。若建立连接只需两次握手,客户端并没有太大的变化,仍然需要获得服务端的应答后才进入ESTABLISHED状态,而服务端在收到连接请求后就进入ESTABLISHED状态。此时如果网络拥塞,客户端发送的连接请求迟迟到不了服务端,客户端便超时重发请求,如果服务端正确接收并确认应答,双方便开始通信,通信结束后释放连接。此时,如果那个失效的连接请求抵达了服务端,由于只有两次握手,服务端收到请求就会进入ESTABLISHED状态,等待发送数据或主动发送数据。但此时的客户端早已进入CLOSED状态,服务端将会一直等待下去,这样浪费服务端连接资源
在这里插入图片描述

2.TCP连接的释放一共需要四步,因此称为*四次挥手

第一次挥手:
若A认为数据发送完成,则它需要向B发送连接释放请求。该请求只有报文头,头中携带的主要参数为:
FIN=1,seq=u。此时,A将进入FIN-WAIT-1状态。
PS1:FIN=1表示该报文段是一个连接释放请求。
PS2:seq=u,u-1是A向B发送的最后一个字节的序号。

第二次挥手
B收到连接释放请求后,会通知相应的应用程序,告诉它A向B这个方向的连接已经释放。此时B进入CLOSE-WAIT状态,并向A发送连接释放的应答,其报文头包含:ACK=1,seq=v,确认号=u+1

PS1:ACK=1:除TCP连接请求报文段以外,TCP通信过程中所有数据报的ACK都为1,表示应答。
PS2:seq=v,v-1是B向A发送的最后一个字节的序号。
PS3:确认号=u+1表示希望收到从第u+1个字节开始的报文段,并且已经成功接收了前u个字节。
A收到该应答,进入FIN-WAIT-2状态,等待B发送连接释放请求,此时从B发送的应该为FIN被置为1的另一个报文段
注:第二次挥手完成后,A到B方向的连接已经释放,B不会再接收数据,A也不会再发送数据。但B到A方向的连接仍然存在,B可以继续向A发送数据

第三次挥手:
当B向A发完所有数据后,向A发送连接释放请求,请求头:FIN=1,ACK=1,seq=w,确认号=u+1。B便进入LAST-ACK状态。

第四次挥手:
A收到释放请求后,向B发送确认应答,此时A进入TIME-WAIT状态。该状态会持续2MSL时间,若该时间段内没有B的重发请求的话,就进入CLOSED状态,撤销TCB。当B收到确认应答后,也便进入CLOSED状态,撤销TCB

为什么A要先进入TIME-WAIT状态,等待时间后才进入CLOSED状态?
为了保证B能收到A的确认应答。若A发完确认应答后直接进入CLOSED状态,那么如果该应答丢失,B等待超时后就会重新发送连接释放请求,但此时A已经关闭了,不会作出任何响应,因此B永远无法正常关闭

客户TCP状态变化
服务端TCP状态变化

六.拥塞控制原理

在实践中,丢包一般是当网络变得拥塞时由于服务器缓存溢出引起的。分组重传因此作为网络拥塞的征兆来对待,但是缺无法处理导致网络拥塞的原因,因为有太多源想以过高的速率发送数据。为了处理网络拥塞的原因,需要一些机制以在面临网络拥塞时遏制发送方。

6.1 拥塞原因与代价

计算机网络拥塞的原因是因为网络中的分组太多,而链路带宽和路由器缓存容量都是有限的;

  • 当分组的到达速率接近链路容量时,分组将经历巨大的排队时延;
  • 发送方必须执行重传已补偿因为缓存溢出而丢弃的分组
  • 发送方遇到大时延时所进行的不必要重传会引起路由器利用其链路带宽来转发不必要的分组副本。
  • 当一个分组沿着一条路径被丢弃时,每个上游路由器用于转发该分组到丢弃该分组而使用的传输容量最终被浪费掉了;

6.2 拥塞控制方法

1.拥塞控制:拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况;
2.流量控制:流量控制是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收。

总体来说,我们可以更具网络层是否为传输层拥塞控制提供了显式帮助来区分拥塞控制方法:端到端拥塞控制网络辅助拥塞控制

在端到端拥塞控制方法中,网络层并没有向传输层拥塞控制提供显式支持,即便网络中存在拥塞,端系统也必须通过对网络行为的观察(如分组丢失与时延)来判断;TCP必须通过端到端的方法解决拥塞控制,因为IP层不会像端系统提供有关网络拥塞的反馈信息。TCP报文段的丢失(超时或者收到3次冗余确认而得知)被认为是网络拥塞的一个迹象,TCP将相应地减小窗口长度;

在网络辅助的拥塞控制方法里,网络层会向发送方提供关于网络中拥塞状态的显式反馈消息;比如使用一个比特位来指示网络是否拥塞;拥塞信息从网络反馈到发送方一般有两种方式,其中直接反馈信息可以由网络路由器发送给发送方,这种方式的通知通常采用一种拥塞分组的形式;第二种形式的通知是**路由器标记或者更新从发送方到接收方的分组中的某个字段来指示拥塞的产生,然后由接收方向发送方通知该网络发生了拥塞
**。

七.TCP拥塞控制

TCP采用拥塞控制的方法是让每一个发送方根据所感知到的网络拥塞程度来限制其能向连接发送流量的速率。由此引出了三个问题:一个TCP发送方如何让限制它想其连接发送流量的速率;一个TCP发送方如何感知从它到目的地之间的路径上存在拥塞;当发送方感知到端到端的拥塞时,采用什么算法来改变发送速率。

我们知道,TCP连接的双方都维护着两个窗口,其中一个是作为发送方的窗口,也被称为拥塞窗口cwnd,它对发送方能向网络中发送流量的速率进行了限制,last sent-last acked<=min{cwnd,rwnd};另一个自然是作为接收方的接收窗口。我们假设,发送方可以在RTT时间范围内连续发送cwnd个字节的数据,所以发送速率即为cwnd/RTT;发送方通过调整窗口大小来对发送数据的速率加以控制。

我们将TCP发送方的丢包事件定义为:要么超时,要么收到接收方的3个冗余ACK;如果网路拥塞,那么网络中的路由器就会发生缓存溢出,进而导致数据报被丢弃,然后就会引起发送方的丢包事件;此时,TCP发送方就可以认为TCP连接出现了拥塞;另外,TCP将接收方发送的ACK视为网络通畅的标志,如果ACK到达的速率较高,那么TCP的拥塞窗口就会以较高的速率扩大,如果ACK到达的速率较慢,那么TCP拥塞窗口的增加速度也会较慢;因为TCP使用ACK对拥塞窗口做出调节,所以也别称为自计时的

TCP发送速率过高,网络就很容易拥塞;TCP发送方如果过于谨慎,那么就无法充分利用网络的带宽;所以TCP如何设置自己的发送速率,才能使得网络不会拥塞而且还充分利用带宽呢?关于这个问题,TCP使用下列指导性原则回答这些问题:

  • 一个丢失的报文段意味着拥塞,因此当丢失报文段时应当降低TCP发送方的速率
  • 一个确认报文段指示该网络正在向接收方交付发送方的报文段,因此,当收到对先前报文段的确认时,可以增加发送方的速率
  • 带宽检测;TCP调节器传输速率的策略是增加其速率以响应到达的ACK,除非出现丢包,此时才减少发送速率;以为网络中没有明确的拥塞控制状态信令,ACK和丢包事件充当了隐式信号.

以上为TCP拥塞控制的概述,接下来就是广受赞誉的TCP拥塞控制算法,该算法包含三个主要部分:慢启动拥塞避免快速恢复;慢启动和拥塞控制是TCP的强制部分;两者的差异在于对收到的ACK做出反应时增加cwnd长度的方式;快速恢复是推荐部分,对于TCP发送方并非是必须的。

慢启动:
TCP连接在开始的时候,其cwnd常设置为一个MSS,然后在慢启动状态每收到一个ACK,cwnd就增加一个MSS;这样的话,在慢启动阶段,发送速率是指数增加的(1,2,4,8…)
何时结束这种指数增长?有三种情况:发送了超时、发生了冗余ACK以及cwnd达到ssthresh。ssthresh是慢启动阈值的速记;在慢启动阶段,如果发生了超时事件,那么ssthresh就被设置为当前cwnd的一半,然后将cwnd置为1;当cwnd逐步增加到ssthresh时,再翻倍增加cwnd就有一点鲁莽了,所以此时TCP结束慢启动,进入拥塞避免模式。在拥塞避免模式里,TCP将更谨慎地增加cwnd;如果收到冗余ACK,那么TCP会做一次快速重传,然后进入快速恢复阶段;
慢启动
拥塞避免:
一旦进入拥塞避免状态,cwnd的值大约是上次遇到拥塞时的一半,所以TCP在每个RTT中,只将cwnd增加一个1个MSS大小;也就是说在拥塞避免阶段,cwnd是线性增加的

当出现超时时,TCP将cwnd设置为1,然后将ssthresh更新为cwnd的一半;当收到冗余ACK时,TCP将cwnd减半,然后将ssthresh置为cwnd值的一半,并且进入快速恢复状态。

快速恢复
在快速恢复阶段,对于引起TCP进入该状态的缺失报文段,每收到一个ACK,cwnd增加一个MSS;最终,当对丢失报文段的一个ACK到达时,TCP降低cwnd后进入拥塞避免状态;如果出现超时事件,快速恢复在执行如同慢启动和拥塞避免中相同动作后,进入慢启动状态:当丢包事件出现时,cwnd的值被设置为1个MSS,并且ssthresh变为cwnd的一半.

拥塞控制

7.1 公平性

TCP趋于在竞争的多条TCP连接之间提供对一段瓶颈链路带宽的平等分享。
1.公平性和UDP
UDP是没有内置的拥塞控制的,当运行在UDP上时,这些应用能够以恒定的速率将其音频以及视频数据注入网络中并且偶尔会丢失分组,而不愿再拥塞时将其发送速率降至“公平”级别并不丢失分组。

2.公平性和并行TCP连接
通常,Web浏览器通常使用多个并行TCP连接来传送一个Web页中的多个对象。当一个应用使用多条并行连接时,它占用了一条拥塞链路中较大比例的带宽。

7.2 明确拥塞通告:网络辅助拥塞控制

一个TCP发送方不会收到来自网络层的明确拥塞指示,而是通过观察分组丢失来推断拥塞,最近提出一种方案,该方案允许网络明确向TCP发送方和接收方发出拥塞信号,这种形式的网络辅助拥塞控制称为明确拥塞通告。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-20 15:27:26  更:2021-08-20 15:29:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:43:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码