经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 其他 » 职业生涯 » 查看文章
第五章传输层
来源:cnblogs  作者:pinkOrange  时间:2021/5/17 9:12:58  对本文有异议

0.本章思维导图:

img

1.运输层协议概述

1.1进程间的通信

概述

? 运输层向它上面的应用层提供通信服务运输层属于面向通信部分的最高层,同时也是用户功能中的最底层;只有位于网络边缘部分的主机的协议栈才有运输层,而网络核心部分中的路由器在转发时只用到下三层的功能

? 通信

? 真正进行通信的实体是在主机中的进程,是一台主机中的进程和另一台主机中的进程在交换数据,严格来讲,两台主机进行通信就是两台主机中的应用进程互相通信

? 运输层的作用:
img

? 网络层与运输层的区别:网络层为主机之间提供逻辑通信,运输层为应用进程之间提供端到端的逻辑通信

? 基于端口的复用和分用功能

? 复用:在发送方不同的应用进程都可以使用同一个运输层协议传送数据

? 分用:接收方的运输层在剥去报文的首部后能把这些数据正确交付目的应用进程

? 屏蔽作用:运输层向高层屏蔽了网络核心的细节,使应用进程看见的就好像在两个运输层实体之间有一条端到端的逻辑通信信道

*两种不同的运输协议

当运输层采用TCP协议时,尽管下面的网络是不可靠的,但这种逻辑通信信道就相当于一条全双工的可靠信道

当运输层采用无连接的UDP协议时,这种逻辑信道仍是一条不可靠信道

1.2运输层的两个主要协议

? 两个主要协议

? (1)用户数据报协议(UDP)

? (2)传输控制协议(TCP)

? 两种协议在协议栈中的位置
img

? UDP

? 在传送数据之前不需要先建立连接,远地主机收到UDP报文后,不需要给出确认,UDP不提供可靠交付,但某些情况却是最有效的工作方式

? TCP

? 提供面向连接的服务,在传送数据前先建立连接,数据传送结束后要释放连接;TCP不提供广播或多播服务;TCP提供可靠的、面向连接的运输服务,因此增加了很多开销

? UDP与IP数据报的区别

? IP数据报要经过互联网中许多路由器的存储转发

? UDP用户数据报是在运输层的端到端抽线的逻辑信道中传送的

? TCP报文是在运输层抽象的端到端逻辑信道中传送,这种信道是可靠的全双工信道
img

*1.3运输层的端口

目的:把特定主机上运行的进程作为互联网上通信的终点不可行,因为进程的创建和撤销是动态的,因此使用协议端口号作为识别的终点,而不需要知道具体进程

协议端口号(端口):虽然通信的终点是应用进程,但只要把报文交到目的主机的某个目的端口,剩下的工作就由TCP或UDP来完成

两种端口区别

硬件端口:不同硬件设备进行交互的接口

软件端口:应用层的各种协议进程与运输实体进行层间交互的一种地址,此处的端口都是指软件端口

端口的表示:用16位的端口号来标志一个端口;端口号只具有本地意义,只标志本计算机应用层中各进程和运输层交互时的层间接口

*端口号的分类

? 服务器端口号:
? 熟知端口号:0~1023,这些端口号被指派给TCP/IP最重要的以下应用程序,让所有用户都知道

? img

? 登记端口号:1024~49151,为没有熟知端口号的应用程序使用

? 客户端端口号:49152~65535,仅在客户进程运行时才动态选择,因此又叫短暂端口号

2.用户数据报协议UDP

2.1.UDP概述:

UDP的主要特点

? (1)UDP是无连接的:发生数据之前无需建立连接,减少了开销和发送数据之前的时延

? (2)UDP使用尽最大可能交付:不保证可靠交付,因此主机不需要维持复杂的连接状态表

? (3)UDP是面向报文的:UDP对应用层交下来的报文不做处理,直接加上首部后就转发,若报文过长,IP层会进行分片,可能使IP层效率降低
img

? (4)UDP没有拥塞控制:因此网络出现拥塞不会使源主机发送速率降低,对实时应用很重要

? (5)UDP支持一对一、一对多、多对一和多对多的交互通信

? (6)UDP的首部开销小:只有8字节,比TCP的20字节首部短

*2.2.UDP的首部格式:

img

  • 伪首部:只在计算校验和时使用,不参与数据传输

    源端口:源端口号;在需要对方回信时选用;不需要时用全0

    目的端口:目的端口号;在终点交付报文时必须使用

    长度:UDP用户数据报的长度,最小值是8(仅有首部)

    校验和:检测UDP用户数据报在传输过程中是否有错。有就丢弃

img

? 计算UDP校验和:与IP首部检验相似,但UDP的检验和把首部和数据部分一起都检验

?

3.传输控制协议TCP概述

*3.1.TCP的主要特点:

(1)TCP是面向链接的运输层协议:在使用TCP协议之前,必须先建立连接

(2)每一条TCP链接只能有两个端点,每一条TCP连接只能是点对点的

(3)TCP提供可靠交付的服务:保证数据无差错、不丢失、不重复、按序到达

(4)TCP提供全双工通信:允许通信双方任何时候都能发送数据

(5)面向字节流:流指的是流入到进程或从进程流出的字节序列;TCP把应用程序交下来的数据仅看作一串无结构的字节流

? img

TCP连接是一条虚连接(逻辑连接),并不是真正的物理连接

3.2.TCP的连接:

*套接字:套接字=(IP地址:端口号) IP地址拼接上端口号,例如(192.168.1.1:80)

每一条TCP连接唯一被通信两个端点(两个套接字)所确定:

? TCP连接::={socket1,socket2} = {(IP1:port1),(IP2:port2)}

TCP连接的端点不是进程,而是套接字

同一个IP地址可以由多个不同的TCP连接,而同一个端口也能出现在多个不同TCP连接中

4.可靠传输的工作原理:

? 理想传输条件:

? 传输信道不产生差错

? 不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据

4.1.停止等待协议:

? 停止等待:每发送完一个分组就停止发送,等待对方确认,在收到确认后再发送下一个分组

? (1)无差错情况:

? img

? (2)出现差错:

? img

? A只要超过一段时间每收到确认,就默认发送的分组丢失而重传之前的分组,就是超时重传

? 注意:

? (1)A发送完一个分组后,必须暂时保留已发送分组的副本,只有在收到相应确认后才删除

? (2)分组和确认都需要编号,才能明确哪个分组收到确认,哪个没收到

? (3)超时计时器的重传时间应比数据在分组传输的平均往返时间更长一些

? (3)确认丢失和确认迟到:

? 确认丢失:

? img

? 确认迟到:

? img

?

3.2.连续ARQ协议:

? 发送方维持发送窗口,位于发送窗口内的分组都可以连续发送出去,而不需要等待对方确认,这样信道利用率就提高了

? 工作原理:

? img

? ARQ规定,发送方每收到一个确认,就把发送窗口滑动一个分组位置,接收方采用累积确认方式,在收到几个分组后,对按序到达的最后一个分组发送确认

? 优点:容易实现,确认丢失也不必重传

? 缺点:不能向发送方反映出接收方已经正确收到的所有分组信息

5.TCP报文段的首部格式

? 首部格式:

? img

? (1)源端口和目的端口:各占2字节,分别是源端口号和目的端口号

? (2)序号:占4字节,TCP中传输的数据流中的每一字节都有一个编号。序号字段的值是本报文段所发送的数据的第一个字节的序号

? (3)确认号:占4字节,是期望收到对方下一个报文段的第一个数据字节的序号

? 确认号=N,则表明到序号N-1为止所有数据都正确收到

? (4)数据偏移:占4位,指出TCP报文段的数据起始处距离TCP报文段的起始处有多远

? (5)保留:占6位,保留为今后使用

? (6)紧急URG:当URG=1时,表明紧急指针字段有效,告诉系统此报文中有紧急数据,应尽快传送,而不采用原来的按排队顺序来传送

? (7)确认ACK:当ACK=1时确认号字段有效,TCP规定,在连接建立后所有数据报文段都把ACK置为1

? (8)推送PSH:当收到PSH=1的报文时,就尽快交付接收应用进程,而不再等到整个缓存都填满后再向上交付

? (9)复位RST:当RST=1时,表明TCP连接中出现严重差错,必须释放连接,然后重新建立连接

? (10)同步SYN:在连接建立时用来同步序号;当SYN=1而ACK=0时,表明这是一个连接请求报文,对方若同一建立连接,则应在响应报文中使SYN=1,ACK=1

? (11)终止FIN:用来释放一个连接,当FIN=1时,表示此报文段的发送方已经发送完毕,并要求释放连接

? (12)窗口:占2字节,指的是发送本段报文段的一方的接收窗口,窗口值作为接收方让对方设置其发送窗口的依据;窗口字段明确指出了现在允许对方发送的数据量,窗口值经常动态变化

? (13)校验和:占2字节,检验和字段检验的范围包括首部和数据两部分

? (14)紧急指针:占2字节,在URG=1时才有意义,指出本报文段中的紧急数据的字节数

? (15)选项:长度可变,最长40字节

? 最大报文段长度(MSS)

? 是每一个TCP报文段中的数据字段的最大长度,并不是整个TCP报文段的最大长度,是TCP报文段长度-TCP首部长度

*6.TCP可靠传输的实现

6.1.以字节为单位的滑动窗口:

? 根据B给出的窗口值,A构造自己的发送窗口

? img

? 发送窗口表示:在没有收到B的确认时,A可以连续把窗口内的数据都发送出去

? 发送窗口中的序号表示允许发送的序号,窗口越大,发送方就可以在收到对方确认前连续发送更多的数据,因此可能获得更高的传输效率

? 收到新的确认后发送窗口前沿向前移动,没有收到新的确认或收到新的确认但对方通知的窗口缩小了,会使发送窗口前沿不动

? TCP的缓存和窗口的关系:

? img

? 发送缓存存放:

? 发送应用程序发送给发送方TCP准备发送的数据

? TCP已发送出但尚未收到确认的数据

? 接收方缓存存放:

? 按序到达的、但尚未被接受应用程序读取的数据

? 未按序到达的数据

6.2.超时重传时间的选择:

? 加权平均往返时间RTTs

? 新的RTTs=(1-a)(旧的RTTs)+a(新的RTT样本)

? 超时重传时间RTO

? RTO=RTTs+4*RTTd

? RTT的偏差的加权平均值RTTd

? 新的RTTd=(1-b)(旧的RTTd)+b|RTTs-新的RTT样本| 其中b=0.25

? Karn算法:

? 在计算加权平均RTTs时,只要报文段重传了,就不采用其往返时间样本,这样得出的加权平均RTTs和RTO就较准确

6.3.选择确认SACK:

? 选择确认的工作原理

? 接收方在接受对方发送过来的数据字节流的序号不连续,结构就形成了一些不连续的字节块,如果这些字节的序号都在接受窗口内,接收方就先收下这些数据,但要把这些信息告诉发送方,使发送方不再重复发送这些已收到的数据

? img

? 左边界为闭,右边界为开;左边界指向字节块第一个字节序号,右边界指向字节块最后一个序号+1

7.TCP的流量控制

*7.1.利用滑动窗口实现流量控制:

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

滑动窗口的单位:字节

滑动窗口流量控制流程:

? 开始时rwnd=400,每个报文段长100字节

? img

持续计时器:解决盲等死锁。只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器,若计时器到期,就发送一个零窗口探测报文段,而对方就在确认这个报文段时给出了现在的窗口值,若窗口值仍是零,那么收到报文的一方就重新设置持续计时器,若不是零,那么死锁就被打破

7.2.TCP的传输效率:

Nagle算法

? 若发送应用进程要把发送的数据逐个字节地送到TCP发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。当发送方收到对第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文发送出去,同时继续对后到达的数据进行缓存。只有在收到对前一个报文段的确认后才继续发送下一个报文段

糊涂窗口综合征:接收缓存每次只能释放出1字节空间,然后把窗口设为1,向发送方发送确认,发送方又发来1字节数据,接收方发回确认,仍将窗口设为1字节,这样会使网络效率降低

? 解决方法:让接收方等待一段时间,使得接收缓存有足够空间容纳一个最大的报文段,或等接收缓存中有一半空闲空间。此时再发送确认报文

8.TCP的拥塞控制

8.1.拥塞控制的一般原理:

? 拥塞:某段时间,若对网络中某资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏,这种现象称为拥塞

? 出现拥塞的原因:对资源的需求>可用资源

? 增加资源解决拥塞:不能。拥塞由多种因素引起,不能单纯通过增加资源解决

? 拥塞的恶化:如果路由器没有足够缓存空间,就会丢弃一些新到的分组,当分组被丢弃时,发送方就会重传,甚至多次重传,这样会导致更多分组流入网络和被网络中的路由器丢弃

? 拥塞控制与流量控制的区别:

? 拥塞控制就是防止过多的数据注入到网络,这样可以使网络中的路由器或链路不致过载,拥塞控制的前提是网络能够承受现有的网络负荷,拥塞控制是一个全局性过程

? 流量控制是指对点对点通信量的控制,是端到端的问题,流量控制就是抑制发送端发送数据的速率,以便使接收端来得及接收

? 拥塞控制的一般原理:

? 开环控制:就是在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不发生拥塞

? 闭环控制:基于反馈回路概念;检测网络系统以便检测到拥塞在何时、何处发生;把拥塞发生的信息传送到可采取行动的地方;调整网络系统的运行以解决出现的问题

? 检测网络拥塞的指标:

? 由于缺少缓存空间而被丢弃的分组的百分数

? 平均队列长度

? 超时重传分组数

? 平均分组时延

? 分组时延的便准差

*8.2.TCP的拥塞控制方法

拥塞控制算法

? 慢开始

? 拥塞避免

? 快重传

? 快恢复

慢开始和拥塞避免

? 拥塞窗口:大小取决于网络的拥塞程度,并且动态的变化,发送方让自己的发送窗口等于拥塞窗口

? 判断拥塞的依据:出现了超时

? 发送方控制拥塞窗口的原则

? 只要没有出现拥塞,拥塞窗口就可以再增大一些,以便把更多分组发送出去,提高网络利用率;只要发生拥塞,就把拥塞窗口减小一些,以减少注入到网络种的分组数,以缓解网络出现的拥塞

? 拥塞的判断:重传定时器超时、收到三个相同的ACK

? 慢开始算法

? 算法思路:由小到大逐渐增大拥塞窗口数值

? 初始拥塞窗口:初始拥塞窗口设置为1至2个发送方的最大报文段的数值

? 拥塞窗口的控制:在每收到一个对新报文段的确认后,可以把拥塞窗口增加多一个SMSS(发送方最大报文段)的数值,即拥塞窗口cwnd每次的增加量 = min(N,SMSS),N是原先未被确认、现在被刚收到的确认报文确认的字节数

? 算法流程:

? img

? 每经过一个传输轮次,拥塞窗口cwnd就加倍

? 传输轮次:一个传输轮次所经历的时间就是往返时间RTT;即发送n个报文段并受到n个报文段确认总共经历的时间

? 传输轮次更加强调:把拥塞窗口所允许发送的报文段都连续发送出去,并收到对已发送的最后一个字节的确认

? 慢开始:不是指cwnd的增长速度慢,而是在TCP开始发送报文段时先把cwnd设置为1,然后再逐步增大cwnd

? 慢开始门限:防止拥塞窗口增长过大引起网络拥塞

? 用法: 当cwnd<ssthresh时,使用慢开始算法

? 当cwnd>ssthresh时,停止使用慢开始而改用拥塞避免算法

? 当cwnd=ssthresh时,既可用慢开始,也可用拥塞避免

? 拥塞避免算法

? 算法思路:让拥塞窗口缓慢的增大,每经过一个RTT就把发送方的拥塞窗口+1,而不是像慢开始加倍增长

? 拥塞避免特点:加法增大,拥塞窗口按线性规律缓慢增长,比慢开始的拥塞窗口增长速率慢得多

? 拥塞避免不能完全避免拥塞,只是控制拥塞窗口按线性规律增长,使网络不易出现拥塞

? 快重传算法

? 特点:可以让发送方尽早知道发生了个别报文段的丢失

? 算法思路:要求接收方不等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认

? 算法启动:发送方只要一连收到3个重复确认,就立即进行重传(即快重传)

? 算法流程:

? img

? 快恢复算法

? 发送方只是丢失个别报文,不启动慢开始而用快恢复算法,发送方调整门限值ssthresh=cwnd/2,同时设置拥塞窗口cwnd=ssthresh,并开始执行拥塞避免算法

? 拥塞控制流程图:

? img

? 发送方窗口的上限值:发送方的发送窗口一定不能超过对方给出的接收方窗口值rwnd;上限值应取接收方窗口和拥塞窗口这两个变量中较小的一个,即发送方窗口的上限值= min(rwnd,cwnd)

? 主动队列管理AQM

? 略

9.TCP的运输连接管理

? 运输连接的三个阶段:连接建立、数据传送、连接释放

? 客户-服务器方式:TCP连接建立采用客户服务器方式,主动发起连接建立的应用叫客户,而被动等待连接建立的应用进程叫服务器

9.1.TCP的连接建立:

? 三报文握手

? img

? 流程:

? 最初两端TCP进程都处于关闭状态,开始时B的TCP服务器进程先创建传输控制块TCB,准备接受客户进程的连接请求,然后进入收听状态;

? A的TCP客户进程也先创建TCB,然后打算建立TCP连接时,向B发送连接请求报文,这是首部中同步位SYN=1,同时选择一个初始序号seq=x,TCP规定,SYN报文段不能携带数据,但要消耗一个序号,这时TCP客户进程进入同步已发送状态;

? B收到连接请求报文后,若同意建立连接,则向A发送确认。在确认报文中将SYN位和ACK位都置1,确认号时ACK=x+1,同时也为自己选择一个初始序号seq=y。这个报文段也不能携带数据,但同样消耗一个序号,这时TCP服务器进程进入同步收到状态

? TCP客户进程收到B的确认后,还要向B给出确认。确认报文的ACK置1,确认号ack=y+1,而自己的序号seq=x+1。TCP规定,ACK报文段可以携带数据,但如果不携带数据则不消耗序号,这种情况,下一个数据报文段序号仍是seq=x+1。这时TCP连接已经建立,A进入已建立连接状态

? B收到A的确认后,也进入已建立连接状态

? 9.2.TCP连接的释放:

? 四报文握手

img

? 流程:

? 起始时A和B都处于已建立连接状态

? A的应用进程先向其TCP发出连接释放报文段,并停止再发送数据,主动关闭TCP连接,A把连接释放报文段首部的终止控制位FIN置1,序号seq=u,它等于前面已传送过的数据的最后一个字节的序号+1。这时A进入终止等待状态。FIN报文段即使不携带数据,也消耗一个序号

? B收到连接释放报文后发出确认,确认号是ack=u+1,而这个报文自己的序号是v,等于B前面已传送过的数据的最后一个字节的序号+1。然后B进入关闭等待状态,TCP服务器进程通知高层应用进程,因而从A到B这个方向的连接就释放了,这时的TCP连接处于半关闭状态,即A已经没有数据要发送了,但B若发送数据,A仍要接受

? A收到来自B的确认后,进入终止等待2状态,等待B发送的连接释放报文段

? 若B已经没有要向A发送的数据,应用进程就通知TCP释放连接,此时B发出的连接释放报文段FIN=1,假定现在B的序号为w,B还必须重复上次已发送过的确认号ack=u+1,此时B进入最后确认状态,等待A的确认

? A在收到B的链接释放报文后,必须对此发出确认,在确认报文段中把ACK置1,确认号ack=w+1,而自己的序号时seq=u+1,然后进入时间等待状态。此时TCP连接还没有释放,必须经过时间等待计时器设置的时间2MSL后,A才进入关闭状态。

? A等待2MSL时间的原因:

? 保证A发送的最后一个ACK报文段能够到达B

? 防止已失效的连接请求报文段出现在本连接中

? TCP的有限状态机

? 略

习题

9.端口的作用是什么?为什么端口划分为三种?

解:端口是对进程进行的一种标识,使不同操作系统的应用进程能互相通信

? 数值端口:0~1023,标记常规的服务进程;

*考:服务对应的端口是对的,常规的熟知端口号对应服务

10.伪首部的作用

解:计算运输层数据报校验和

*考:udp在计算校验和的时候,除了……还要伪首部

*13一个UDP用户数据的数据字段为8192字节。在数据链路层使用以太网来传送,应当划分为几个IP数据片?说明每一个IP数据报段长度和片偏移字段的值

解:6个;数据字段长度:前5个是1480字节,最后一个是800字节。片偏移字段的值是:0,1480/8=185,2960/8=370,4440/8=555,5920/8=740,7400/8=925

|8|8192| ->UDP数据报

20| 8200 | ->IP数据报

20| 1480 | ->MAC帧 8200/1480=5......800 所以分成6片

解析:8192的数据+8字节UDP首部=8200;在MAC帧中,数据部分最大长度1500字节,而UDP还要封装进IP数据报中,IP数据报首部最小20字节,所以一次能传输最多的数据即1500-20=1480;8200/1480=5......800,因此分成6片,前5片数据字段长1480字节,最后一片长800字节;片偏移字段分别为0、185、370、555、740、925

*22.主机A向主机B发送一个很长的文件,其长度为L字节,假定TCP使用的MSS有1460字节

(1)在TCP的序号不重复使用的条件下,L的最大值是多少?

(2)假定使用上面计算出文件长度,而运输层、网络层和数据链路层使用的首部开销共66字节,链路的数据流位10mb/s,求这个文件所需的最短发送时间

解:

(1)L_max=2^32=4GB 因为序号字段32位,最大就是2^32

(2)满载分片数:Q={L_max/MSS}=2941758 发送的总报文数

? 总字节数:N=Q(MSS+66)+{(L_max-QMSS)+66}=4489122708+682=4489123390

? 发送所需时间:N8/(1010^6)=3591.3秒

23.主机A向主机B发送了两个TCP报文段,其序号分别为70和100,求:

(1)第一个报文段携带了多少个字节的数据

(2)主机B收到第一个报文段后发回的确认号应该是多少?

(3)如果主机B收到第二个报文段后发回的确认号是180,试问A发送的第二个报文段中的数据有多少字节?

(4)如果A发送的第一个报文段丢失了,但第二个报文段到达了B。B在第二个报文段到达后向A发送确认,问这个确认号是多少?

解:

(1)第一个报文段的数据序号是70到99,共30字节数据

(2)确认号应为100

(3)80字节;180-100=80

(4)70

*37.在TCP的拥塞控制中,什么是慢开始、拥塞避免、快重传和快恢复算法?这里每一种算法起什么作用?乘法减小和加法增大各用在什么情况?

解:

慢开始:开始时将拥塞窗口设为一个很小的值,如一个最大报文段MSS,在每收到一个对新的报文段的确认后,将拥塞窗口增加最多一个MSS的值,这样逐步增大发送端的拥塞窗口

拥塞避免:当拥塞窗口大于拥塞门限时,停止使用慢开始而改用拥塞避免算法。每次使拥塞窗口每经过一个RTT就增加一个MSS的大小

快重传:发送端收到连续三个重复ACK即判定有分组丢失,不等待超时而直接重传报文

快恢复:当发送端收到连三个重复ACK时,就重新设置慢开始门限,同时将拥塞窗口设置为慢开始门限,然后执行拥塞避免

?

乘法减小:不论在慢开始阶段还是拥塞避免阶段,只要出现一次超时,就把慢开始门限设置为当前拥塞窗口值*0.5,当频繁出现拥塞时,慢开始门限值就下降得很慢,以大大减少注入到网络中的分组数

加法增大:执行拥塞避免后,在收到对所有报文段的确认后,就把拥塞窗口增大一个MSS大小,使拥塞窗口缓慢增大,防止网络过早出现拥塞

41.用TCP传送512字节的数据。设窗口为100字节,而TCP报文段每次也传送100字节数据。再设发送方和接收方的起始序号分别选为100和200,画出类似图5-28的工作示意图。从连接建立阶段到连接释放都画上

解:img

————————————————
版权声明:本文为CSDN博主「Ogmx」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43093481/article/details/86684098

原文链接:http://www.cnblogs.com/pinkOrange/p/14755570.html

 友情链接: NPS