zoukankan      html  css  js  c++  java
  • 计算机网络自顶向下学习笔记之(应用层传输层)

    计算机网络学习笔记

    网络核心概念

    时延

    为了从源端系统向目的端系统发送一个报文,源将长报文划分为较小的数据块,称之为分组

    每个分组都通过通信链路和分组交换机,分组交换机常见的有两类:路由器链路层交换机

    考虑经过一条链路转发一个大小为L比特的分组,链路的传输速率为R比特/秒,那么这个分组经过这条链路的时延为L/R

    如果两个端系统之间N条这样的链路,端到端的时延为

    d端到端=(N*L)/R
    

    N=源端口和目的端口之间的路由器数量+1

    实际网络环境中的时延还包括了:

    • 处理时延,也就是源主机和路由器接收到分组并将它成功转发出去的时延
    • 传播时延,也就是数据在物理媒介中的传播时延
    • 排队时延,有可能路由器比较忙,分组需要在路由器中等待,这里就会有个排队时延
    • 传输时延,也就是我们上面讲述的L/R

    一般在不考虑网络状况拥堵,也就是忽略排队时延,以及不考虑端到端的传播时延,因为现在都是光纤,光速老B快了,也不太考虑处理时延的情况下,一般讨论的时延也就是上述定义的端到端时延

    协议分层

    为什么需要分层?

    个人理解:

    • 分层更加有利于,整个协议栈的开发和维护,如果不分层的话,可想而知多少代码会耦合到一起,也没法想象怎么在一个整体中同时提供TCP、UDP两种服务
    • 分层更加有利于上层应用的多样性,你开发的应用需要可靠的传输层协议你就整TCP,你需要更高的吞吐量你就整UDP,你的应用对于时延要求很高,你就上UDP,而IP层将统一的提供端到端的不可靠数据传输服务,这是你无需操心的,拿来用就好了
    那么又分为几层呢?

    从黑书上来看,可以分为5层,也可以分为7层

    image.png

    黑书的组织形式是按照五层Internet协议栈来组织的,我们通常所熟知的也是五层Internet协议栈,而7层的网络协议显得没那么必要,5层能干完的活,如果你用7层的话,那如果每个层都来个header,无疑是降低了效率的,更别说还有人觉得5层协议栈都还是很多

    五层协议栈

    先混个脸熟,大致了解一下每层都干了点啥

    应用层

    我们熟知的应用层协议如:HTTP、SMTP、FTP、DNS服务也是基于应用层协议干的,应用层协议就控制应用的行为呗,例如HTTP报文段如果method为OPTION,那么HTTP服务器就会告诉它,我支持什么样的访问方式,这个取决于具体的应用

    运输层

    在两个端系统的应用程序之间传送应用层报文,在Internet中包含了两个运输层协议,TCP和UDP,TCP提供面向连接的可靠的运输层服务,(真的就那么可靠嘛?其实不然),并且还提供拥塞控制、流量控制等等特性,而UDP则提供不面向连接的不可靠的服务,也没有拥塞控制,我们把运输层分组称为报文段

    网络层

    在两个端系统之间传送运输层报文,网络层协议包括了著名的IP协议,网络层还包括了路由选择协议,目前就把它当成一个黑盒子就完事儿了,它可能能完成端到端的数据交付

    链路层

    将整个从一个网络元素移动到下一个网络元素

    物理层

    物理层将该中的一个比特从一个网络元素移动到下一个网络元素

    应用层

    生活中常见的应用层协议很多,例如HTTP,SMTP,FTP等等,但是在互联网时代还是着重了解HTTP吧

    可供选择的运输层服务

    • 可靠的数据传输

      我们都知道,分组在路由器缓存存不下了会被直接抛弃,数据本身可能出现比特差错,也有可能乱序到达目的主机,而可靠传输保证了所送即所得,也就是源主机发送了啥,在不考虑源主机与目的主机之间网络瘫痪等的原因,源主机发送了啥,目的主机的进程就受到啥,这就是所谓的可靠数据传输,在完整性要求高的应用中,例如web应用,文件传输,邮件发送都需要采用可靠的数据传输服务

    • 吞吐量

      吞吐量,也就是发送进程向接收进程交付比特的速率,通常吞吐量要求的应用称之为带宽敏感的应用,例如常见的多媒体应用等

    • 定时

      也就是在一定时延内,发送方注入套接字的数据必须达到接收方,例如音视频通话,多人在线游戏通常对实时性要求比较高

    • 安全性

      也就是源主机与目的主机之间通信的数据是被加密的,只能发送到另一方才解密。

    以下为常见的应用对运输层服务的需求:

    image.png

    TCP、UDP以及SSL提供了什么样的服务?

    TCP

    • 面向连接的服务,任何两个主机通信之前需要建立连接
    • 可靠的数据传输服务,其实就是通过重传分组来保证可靠的数据传输的,但是它真的真的就可靠吗?不一定好吧,运输层再说

    UDP

    • 不面向连接,也不保证可靠的数据传输,有没有拥塞控制,那么是不是就是一无是处了呢?当然不了, 由于可靠传输面向连接的特性都是需要利用计算机资源来保持的,而UDP啥也没有,自然也就比TCP更加轻量级,同时它并没有拥塞控制,意味着它可以用它选定的任何速率向网络层发送报文段

    SSL(Secure Socket Layer)

    为了保护安全和隐私,专家们在应用层对于TCP进行了一波增强,使其具有安全性,在一个应用使用SSL的时候,SSL受到应用层的数据加密之后再交给TCP套接字,而在接收端,TCP套接字中读取到数据之后,先通过SSL解密然后交付给应用层

    以下为常见应用所选择的运输层协议

    image.png

    HTTP概况

    对象

    一个对象是一个文件,诸如一个HTML文件,一个JPG类型的图片,一个Java小程序,一个视频片段等等,并且它们每一个都可以通过URL来寻址,多数Web页面含有一个HTML基本文件以及几个引用对象

    无状态

    HTTP是无状态的,也就是说如果特定的客户端在短短几秒内两次甚至数次请求了同一个对象,那么HTTP服务器并不会因为刚刚响应过了这个请求而不再做出反应,仍然会响应这个请求(当然,前提是这个请求能够到达HTTP服务器,它有可能直接被缓存了),所以说HTTP协议是无状态

    非持久连接和持久连接

    非持久连接

    HTTP是基于TCP的,而非持久连接的意思就是,我一次请求过后我就直接把TCP连接断了,每个请求/响应对是经一个单独的TCP连接发出,而持久连接就是,所有的请求以及响应共用同一个TCP连接

    假设一个web页面包含了HTML基本页面和10个图片,那么采用非持久连接的请求方式就是这样的

    1. HTTP客户进程在80端口发起一个到服务器的TCP连接
    2. HTTP客户进程发起请求
    3. HTTP服务器进程发送响应
    4. HTTP服务器进程active close
    5. HTTP客户端进程passive close
    6. HTTP客户端进程打开HTML文件发现好家伙还有10个图片的URL,然后又重复上面的步骤10次

    浏览器自然是允许并行的TCP连接的,但是上述过程的响应时间任然是很长的

    以下为请求并接收一个HTML文件所需的时间估计

    image.png

    如果按照非持久连接的方式来考虑的话,在并行度为1的情况下,上述web页面完全加载需要耗费长达22个 RTT,而持久连接的方式呢?显而易见,只需要2个RTT,孰强孰弱不由分说

    RTT(Round-Trip Time)往返时间,发起连接的第三次握手可以携带数据了

    持久连接

    从上面可以看出非持久连接的一些问题

    • 响应时间长,即使浏览器允许并行连接的情况下,响应时间仍然是持久连接的数倍
    • 连接的建立需要在客户端和服务器端分配缓冲区和变量来,而拆除又要对这些空间进行回收,客户端倒是还好,你自己一个人用,服务器端频繁地对连接进行拆除和建立是非常浪费性能的行为

    而持久连接可以对一个web页面的所有对象共用同一个TCP连接,甚至多个web页面共用同一个TCP连接,一般来说,如果一条连接超过一定时间间隔仍然未被使用,那么HTTP服务器就会关闭该连接

    HTTP报文格式

    请求报文格式

    经典请求报文格式如下:

    GET /somedir/page.html HTTP/1.1
    Host:www.someschool.edu
    Connection: close
    User-agent: Mozilla/5.0
    Accept-language: fr
    

    主要分为了以下几个部分:

    请求行:主要包含三部分信息

    • 请求方法:GET,请求方法还有POST、DELETE、HEAD、PUT、OPTION
    • URL
    • 协议版本

    其他的行称之为首部行

    • Host:奇怪明明已经建立TCP连接了,为什么还需要Host??这是Web代理高速缓存所要求的

    • Connection:close 告知服务器,采用非持久连接

    • user-agent: Mozilla/5.0 告诉服务器,我使用的客户端浏览器是啥,你最好根据这个来返回我能够兼容的html页面,否则的话返回默认

    • Accept-language: 告诉服务器,我需要什么语言的html,你拿这个版本给我,没有的话,走默认

    以下为Http请求报文的结构示意图:

    image.png

    使用get方法时,请求正文也就是实体主体通常为空,如果方法为post,或者put,对应着表单的提交,表单中填写的项目就被放入了请求正文中

    head方法类似于get方法,但是head方法并不返回请求对象,只返回响应头信息,也就是Http报文头,常用来进行调试跟踪

    响应报文格式

    http响应

    一个典型的http响应如下:

    HTTP/1.1 200 OK
    Connection: close
    Data: Tue,09 Aug 2011 15:44:04 GMT
    Server: Apache/2.2.3(Centos)
    Last-Modified: Tue, 09 Aug 2011 15:11:03 GMT
    Content-Length: 6821
    Content-Type: text/html
    
    (data ...)
    

    它包含了三个部分:

    1.初始状态行:HTTP/1.1 采用HTTP协议的1.1版本 200 OK 代表了这次请求响应成功 还有其他的状态码可自行查看,例如常见的404 not found 500 internal server error

    2.6个首部行:

    Connection: close

    Data:Tue,09 Aug 2011 15:44:04 GMT 响应的日期

    Server: Apache/2.2.3 (Centos) 服务器,在Centos环境下的Apache服务器

    Last-Modified: Tue,09 Aug 2011 15:11:03 GMT 指示了对象创建的时间或者最近一次修改的时间,这个主要是为了缓存更新而设置的

    Content-Length: 指示了被发送对象的字节数

    Content-Type:指示了被发送对象的类型,为html文本,现在流行的RESTful风格多采用JSON格式返回数据,到时候这里返回的就是JSON了

    由于HTTP协议是无状态的,但是为了适应新的web需求,HTTP在RFC6265中定义了cookie

    cookie技术有四个组件:

    1.在HTTP响应报文中的一个cookie首部字段

    2.在HTTP请求报文中的一个cookie首部字段

    3.在用户端系统中保留一个cookie文件,由用户的浏览器保存

    4.位于web站点的一个后端数据库

    常见的cookie使用方式如下:

    image.png

    web缓存

    也就是在局域网内利用缓存服务器来降低带宽压力和提高服务质量,通过缓存服务器构建的CDN(内容分发网络)就是如此

    它是如何做到的呢?

    image.png

    假设机构网络的平均访问速率为15个请求/s,每个请求对象的平均长度为1Mb,那么局域网上的流量强度为

    (15个请求/s)*(1Mb/请求)/(100Mbps)=0.15
    

    而接入链路上的流量强度为

    (15个请求/s)*(1Mb/请求)/(15Mbps)=1
    

    这就很吓人了,如果流量强度接近1的话,也就是它的到达速率接近链路的发送速率,那么它的排队时延将会无限大,要想降低流量强度,显然需要升级接入链路,然而升级接入链路带宽的费用是非常昂贵的

    而加入了web缓存之后又是什么情况呢?

    image.png

    如果缓存的命中率为0.4,也就是又40%的请求被缓存器缓存了,直接响应,那么直接瞬间将接入链路上的强度将为了0.6,而流量强度与排队时延成指数型上升,这个时候排队时延就很小了,主要的时延就变成了因特网时延,并且由于缓存的加入,减少了对Internet的直接访问,还降低了整体的请求时延,可谓是老八蜜汁小汉堡,即实惠又管饱!!!

    缓存过期怎么办?条件get

    有了缓存web虽然可以降低时延,但是可能导致一个问题,就是请求的对象副本过期了,这个时候就需要我们的条件GET出马了,在请求头的首部行添加一个字段

    If-Modified-Since: Wed,7 Sep 2011 09:23:24 
    

    它是这样工作的

    第一步:客户端浏览器请求服务器某个页面,这个时候还没有缓存

    GET /fruit/banana.gif HTTP/1.1
    Host: www.exotiquecuisine.com
    

    第二步:请求经过缓存服务器到达真正处理请求的服务器,然后响应如下

    HTTP/1.1 OK
    Date: Sat,8 oct 2011 15:39:29
    Server: Apache/1.3.0 (Unix)
    Last-Modified: Wed , 7 Sep 2011 09:23:24
    Content-Type: image/gif
    
    data...
    

    第三步:这个时候,缓存服务器已经有了这个对象的副本了,然后你过两天去请求这个页面

    缓存服务器就会使用到 If-Modified_Since这个首部字段了

    它会向真正处理请求的服务器发出带有该首部字段的请求

    你可能会有疑问,这里不也是向Internet发起请求了嘛?但是它没请求对象呀,它没有那个1Mb的对象呀,自然占用不了多少接入链路的带宽

    //请问自从我上次受到的Last-Modified日期之后你们有更新嘛?
    GET /fruit/banana.gif HTTP/1.1
    Host: www.exotiquecuisine.com
    If-Modified-Since: Wed , 7 Sep 2011 09:23:24
    
    

    第四步:如果这个时候处理请求的服务器,检查发现没有更新,他就会发送一个这样的响应

    HTTP/1.1 304 Not Modified
    Date: Sat, 8 Oct 2011 15:39:29
    Server: Apache/1.3.0 (Unix)
    (empty entity body空的实体主体)
    
    

    这个时候缓存服务器就知道了,没有更新过,直接返回自己缓存的对象就可以了,如果更新了,那么就返回新的副本,然后缓存服务器再缓存就好了,没想到一直很疑惑的请求重定向304在这里出现了

    DNS:因特网的目录服务

    人们更加习惯于记忆主机名,例如www.baidu.com,但是机器更加适合处理定长的IP地址,那么从主机名到IP地址的映射,就需要依靠DNS(Domain Name System)

    DNS:

    1.是一个由分层的DNS服务器实现的分布式数据库

    2.一个使得主机能够查询分布式数据库的应用协议,DNS协议运行在UDP之上,采用53号端口

    DNS的层次结构

    1.根DNS服务器

    2.顶级域DNS服务器

    3.权威DNS服务器

    具体结构如下:

    image.png

    具体到本地还有本地DNS服务器,那么具体将域名映射成IP的过程大致为:

    1.请求本地DNS

    2.本地DNS请求根服务器

    3.根服务器告知本地DNS服务器TLD服务器地址

    4.本地DNS请求TLD服务器地址

    5.TLD服务器告知权威服务器地址

    6.本地DNS请求权威服务器地址

    7.权威服务器告知你要访问的域名对应的IP

    8.本地服务器告诉你要访问的域名对应的IP

    DNS缓存

    就不细说了,提高DNS服务的效率和速度,由于域名和IP的绑定关系通常不是固定的,DNS缓存一般会在两天后失效

    运输层

    关键功能:
    1.将网络层的在两个端系统之间的交付服务拓展到运行在两个不同端系统上的应用层进程之间的交付服务 运输层的基本功能 运输层的多路复用与多路分解

    2.如何在不可靠可能或丢失或者损坏数据的媒体上可靠地通信 TCP支持可靠传输

    3.控制运输层实体的传输速率以避免网络拥堵,或从拥塞的网络中恢复过来 TCP支持拥塞控制

    多路复用和多路分解

    多路分解:将运输层报文段的数据交付到正确的套接字称为多路分解

    多路复用:在源主机从 不同套接字中收集数据块,并为每个数据块 封装首部信息(也就是运输层控制信息)从而生成报文段,然后将报文段传递到网络层,所有这些工作 称为多路复用

    如何实现多路复用,也就是如何去标识不同的socket呢?

    用两个字段: 源端口号字段目的端口号字段

    端口号是一个16比特的数,它的大小在0-65535之间,0-1023范围的端口号号称周知端口号,是受限的,留给了通用的应用例如web服务的80端口,ftp应用的21端口

    还有一些其他的首部字段,具体结构如图所示:

    image.png

    一个UDP套接字是由一个二元组来唯一标识的:

    目的IP地址和目的端口号,只要两个报文段具有相同的目的IP地址和目的端口号,那么他们就会通过相同的目的套接字被定向到相同的目的进程

    但是UDP还是需要源端口号和源IP地址的,为了双工通信,也就是A给B发送报文段的时候会带有A的IP地址和A上运行的进程的端口号,以便B能给A回消息

    而一个TCP套接字是由一个四元组来唯一标识的:

    目的IP地址和目的端口号,源IP地址和源端口号

    为啥TCP和UDP就不同呢??

    因为TCP面向连接,它需要为每个连接负责,实现可靠的数据传输,而实现可靠的数据传输需要相应的数据结构来保存一些TCP变量,每个连接的状态自然是不一样的,自然是不能使用同一个连接 ,你不能说只要目的IP地址和目的端口号相同就共享一个socket吧,TCP不是这样的人!!!

    UDP概述

    假如让你设计一个不提供不必要服务的最简化运输层协议,那么很简单,把网络层收到的数据报分发给对应的进程,把应用层的报文直接交给网络层,那么很简单,我们只需要实现最简单的多路复用多路分用,也就是如UDP那样用两个字段标识一下就好了,也就是目的IP和目的端口号,它在发送报文段的时候不需要握手什么的,直接发送报文就好了

    UDP报文段结构与各首部字段的功能如下:

    image.png

    • 源端口号用于双工通信
    • 目的端口号用于多路分解
    • 长度指示整个UDP报文段长度(包括首部)
    • 检验和用于差错检测

    相较于TCP,UDP的好处

    • 关于何时,发送什么数据,应用层控制更为精细

      由于UDP几乎没有任何发送数据上的限制,也不进行拥塞控制,所以应用进程只要需要发送数据,它就可以将数据交给UDP套接字,UDP套接字就会帮他发送出去

    • 不需要三次握手降低了时延

      很显然,由于UDP不面向连接,它随时都可以直接发送payload,天然比TCP少一个RTT的时延

    • 无连接状态

      连接的保持需要消耗服务器的系统资源,而UDP无需建立连接,自然就减少了对于服务器资源的消耗,因此能支持更多的连接数量

    • 分组首部开销小,TCP报文段首部有20字节,而UDP首部只有8个字节

    UDP可能面临什么样的问题呢?

    没有拥塞控制的UDP协议不限制每个主机发送报文段的数量,如果一个流式多媒体应用采用这样的UDP协议,如果每个人都开很高清的视频的话,就会有大量的UDP报文段进入网络,那么路由器就会就会有大量的分组溢出,这样的结果就是,没人能看到了高清的视频,甚至还会影响正常的TCP通信,导致整个网络的瘫痪,这个有点死锁那味儿了!!!

    一步一步构建可靠传输协议

    1.0经完全可靠的信道传输

    经完全可靠的信道传输:rdt1.0(reliable data transfer)也就是说网络层及其以下层提供的信道是可靠的

    状态机如下:

    image.png

    非常的easy啊,传输层啥事都不用干奥,直接往网络层塞数据就完事儿了,看看状态机就好了(rdt表示可靠数据传输,udt自然就是不可靠数据传输了)

    2.0经具有比特差错信道的可靠数据传输

    状态机如下:

    image.png

    这会儿已经加入了ACK、NAK来表示接收到的分组是否有比特差错

    比特差错的检测通过首部字段中的校验和来检测,不细说了。

    发送方状态迁移:

    1.发送报文段,迁移到等待ACK或者NAK状态

    ​ 1.1受到ACK,迁移回等待上层调用状态

    ​ 1.2受到NAK,在重传当前分组,然后继续等待ACK

    接收方状态迁移

    就一直接收就好了,如果收到有比特差错的报文段,发送NAK标志就好了

    那2.0有什么缺陷呢?

    冗余分组,详见下面的思考

    关于收到NAK之后发送方应该如何处理的思考

    1.发送方再向接收方询问:你到底接收到了没啊?也就是再去请求发送一次ACK或者NAK,但问题是如果这个请求也发生了比特差错呢?那接受方又得问:你又给我发了什么呀?那这样就子子孙孙无穷尽也了,

    2.增加足够的检验和比特,不管差错检测,还进行差错恢复

    3.如果收到了模糊的ACK或者NAK,那就不管,就再发一次之前的分组,就eng发,发到你吐,如果是听到模糊的NAK,重发还好,如果是听到了模糊的ACK(模糊ACK就是说返回的ACK数据包又发生了比特差错,这里不考虑丢包,那么sender就不知道自己发送的被成功接收到了没,只能eng发了),那么就会造成冗余分组的问题,这就带来了2.0版本的升级版2.1

    2.1

    在2.0版本之上,增加了一个比特来表示,接受方要接收一个新的分组还是之前的那个分组,那么现在的状态机就是这样的了:

    image.png

    image.png

    状态机直接芜湖超级加倍了,自然了需要考虑两个分组了嘛,大致情况和2.0相同,看看状态的状态迁移event就好了

    2.2

    在2.1的版本之上进行了化简,能不能只使用ACK确认呢,也就是不用NAK确认,那么就是这样,接收方对于接受到的正确分组,发送一个ACK确认,对于接受到的有比特差错的分组,发送两个ACK确认,也就是冗余ACK(duplicat ACK)

    3.0经具有比特差错的丢包信道的可靠数据传输

    到目前为止,如果发生了比特差错,也能重传了,那么如果发生丢包呢?

    如果发送方给接收方发送的分组丢失了,有可能由于路由器溢出或者别的啥,或者说接收方收到了分组,但是接收方回复的ACK确认丢失了怎么办呢?

    重传,因为2.2通过序号机制已经解决了分组冗余的问题,那么这个时候重传是解决一切问题的万用胶,就重传就好了,那么过多久重传呢?

    规定一个计时器就好了,超过了还没收到ACK确认就重传它,最少要等上个 往返时延加上接收方处理一个分组的时间吧,这个自己去规定就好了

    加上计时器,就成了3.0版本了,此时它的状态机就如下所示了:

    image.png

    这个时候这个协议已经能够实现了我们所期望的可靠传输了,但是它有一个很大的问题,就是性能问题,它是一个停等协议,也就是说如果A发送了一个分组0,它需要等到接收方B发送0号分组的ACK之后,它才能去发送下一个分组1,而一个报文段最多传输1440字节,你这它的整个过程就如下图所示了:

    image.png

    image.png

    看起来想什么,公园老头下象棋呀,你一步我一步的,可想而知传输完一个报文,需要等多少次呀,这可太慢了!!

    流水线协议

    有了上面的了解之后,虽然是能构建一个可靠的传输协议了,但是性能肯定是不过关的,怎么办?停等协议怎么能行?流水线作业!!!不许偷懒

    流水线来了以后自然是好了,效率上去了,但是还带来了问题:

    • 一个比特位来表示序号自然是不够了的,需要增加序号范围,使得每个报文段都有自己的序号
    • 乱序就来洛,由于之前是停等的,老邓头下棋一步棋之前要确保老邓头之前的下棋被老张头看到了,免得老张头返回,现在不停等了,老邓头疯狂下,由于网络状况的变换,每个报文段到达的时间可能不太相同,就有可能产生后来的先了的情况,也就是乱序到达,TCP中通过整流器来解决,例如cs144lab2中实现的stream reassembler
    • 这么多个包是不是意味着,每个包都需要用一个定时器来跟踪呢?当然不是,用一个定时器来跟踪最早发送切还未被确认的包就好了
    • 对于流水线协议如何处理丢包,损坏也就是比特差错以及最重要的超时呢?通常有两种方法回退N步以及选择性重传(SR协议)
    出了岔子怎么办?

    回退N步协议(GBN)也就是滑动窗口协议

    此时发送方看到的序号是这样的

    image.png

    限制窗口大小主要是为了流量控制,注意奥不是拥塞控制奥

    接收方的动作:

    接收方只接收当前想要的那个分组,其他的统统扔了,也就是会丢弃所有失序分组

    发送方的动作:

    • 上层调用,如果窗口没满就发送数据,然后把数据缓存在窗口里面
    • 收到ACK,对序号为n的分组采取累计确认,也就是说收到序号为n的分组的ack了,代表接收方接收了n以及n以前的所有分组
    • 超时,重传所有发送还未确认的分组,这也就为GBN协议埋下了最大的隐患

    回退N步协议,也就是滑动窗口协议的优缺

    优点:

    • 接收方不用缓存,只接收下一个期待的分组,所有乱序的分组都被抛弃,所以接收方的结构简单

    缺点:

    • 由于接收方不缓存乱序分组,那么就把压力完全交给了发送方,发送方可能需要多次重发一个分组,即使接收方收到了,并且这个分组也是完好的
    • 回退N步可太难受了,有些包可能只是由于网络原因还没有到,你这边又给他重发了一次,如果这个N很大的话,那发送方需要多做很多无用功,最难受的点在于,单个分组的差错会导致大量的分组重传

    SR协议 选择性重传协议

    现在接收方也要缓存了,不能让接收方那么任性,乱序到达的包只要符合窗口的要求,就会被放入缓存中

    SR协议的窗口状态就是这样的了

    image.png

    它的发送方处理方式就是这样的了

    • 从上层接收数据,检查是否符合窗口的要求然后再发送
    • 收到ACK,检查这个分组的序号是否落在窗口内,如果是的话则将它标记为已经接收,如果这个序号恰好是send_base的话则移动窗口的左边,如果移动过程发现还有没发送的分组,发送它
    • 超时,由于不回退N步了,所以超时就只发送一个分组,所以每个分组都需要有自己的定时器

    它的接收方的处理方式如下:

    • 只要符合窗口的要求,就接受它,如果他是recv_base,则从recv_base把连续的报文交给上层应用,并且发送ack回去

    它的优缺点呢

    好处:

    • 不再回退N步了,自然就少了很多没必要的重传

    缺点:

    • 接收端结构复杂
    • 需要N个定时器同时计时,这无疑非常之麻烦

    TCP如何处理的呢?

    TCP其实综合两者的长处,tcp_receiver同样需要缓存符合窗口要求的乱序分组,ack也采取累计确认的方式,失序的分组虽然到达了,但是只会缓存在tcp_receiver中,发送的ACK采用GBN的方式,tcp_sender只使用了一个计时器,只追踪最早发送并且尚未确认的分组,超时了也不会重发所有尚未确认的分组,只重发最早发送并且尚未确认的分组

  • 相关阅读:
    为什么做java开发的公司需要那么多程序员?
    一篇文章了解架构设计的本质
    深入理解 Java 多线程核心知识
    面试经验总结:注意这几点,面试通过率上涨30%
    程序员一般做到多少岁,那些70后的程序员都消失了?
    连阿里都在用它处理亿万级数据统计,论其对Java程序员的重要性!
    【源码】HashMap源码及线程非安全分析
    基于框架的RPC通信技术原理解析
    如何写好一份技术简历?
    彻底理解Netty,这一篇文章就够了
  • 原文地址:https://www.cnblogs.com/danzZ/p/13949450.html
Copyright © 2011-2022 走看看