TCP/IP协议学习笔记(三)

对于以太网(数据链路层而言),由于是广播的发送方式,那么共享信道上所有的主机能接收到数据帧,那么通信双方的IP地址都是知道的,但是物理地址只有本主机自己知道,别的主机不知道,所以物理地址具有的是本地性,而IP地址则是全局性的。

由于不知道对方的MAC地址,就不能封装成帧,既而也不能在物理网上传输,(带有IP地址的部分的IP数据报封装在帧的数据字段部分)所以需要获得对方的MAC地址才能封装成帧。

但是目的MAC地址只有目的主机自己知道,所以就要解决这个难题。地址解析由此而生:

因为只有IP地址是双方都知道的,所以要有个桥梁来将IP地址转换为MAC地址,也就是地址解析。IP地址是属于逻辑地址,MAC是属于物理地址。

因此有专门的表记录这种IP地址对应MAC地址的映射关系。静态映射只能手动人工设置,这会出现些麻烦,网卡改变时候MAC地址变了,那么要修改。还有些情况,设备网卡不变,但是在网路中的位置改变了,由于IP地址是标识设备的网络连接,那么必然要修改IP和MAC的映射。

所以采用某些协议来形成动态映射是非常方便的。ARP就是一种地址解析协议。

以太网内每个节点都会有一张ARP高速缓存表,工作的时候,源主机以广播的形式发送请求,请求中带有目的主机的IP地址,目的主机收到后,目的IP不对应的主机会丢弃分组,会将自己的MAC地址填入响应报文中返回(以单播形式)给源主机,这时候源主机就会在自己的ARP缓存表上填入目的主机的MAC地址,此时目的MAC地址和目的IP绑定(在表上)。

ARP分组格式:

                                                                       

ARP协议虽然归在IP层,但它更合适归在网络层和数据链路层的之间,它的报文格式,从左到右起,第一个字段是物理网络的类型(比如以太网,令牌环网),第二个字段是协议类型(像IP,ARP),第三个字段是物理地址长度,第四个是是IP地址长度,第五个字段是操作类型,请求操作值为1,响应操作值为2。然后蓝色部分是源MAC地址和源目的地址,黄色部分是目的MAC和IP地址,由于目的MAC地址是不知道的,所以是未填满的状态。

                                                                              图一 

ARP分组的长度是由前4个字段确定的,也就是说ARP分组的长度是随变化而变化,不固定。

由以上图一可知,ARP只有28字节,但是以太网帧中最小限制是46字节,那么为了达到要求,必须要有填充。

PS:上图中,2个字节的是长度类型字段,用长度来区分协议的种类。如上图,类型为IP分组的,值为0x0800,如果是ARP,值为0x0806。

IP分组和ARP分组的交互:

ARP不是端到端的操作协议(源到目的),因为它的作用决定了它是一个不断请求MAC地址的过程协议。它不像IP是可以跨多个网络。比如从源跨3个物理网到目的,那么每两个物理网之间会发生一次ARP的请求。

IP协议和ARP协议的配套使用过程:

第一种情况是不需要跨越路由器,仅在局域网内:

如上图,当主机A向主机B发送分组的时候,主机A首先根据目的IP地址查自己的路由表,发现是直接交付,那么就要封装成帧,但由于是未绑定关系没有目的MAC地址,那么主机A会将这个分组和目的IP地址一起交给ARP模块,所以ARP收到两个信息。主机A去查ARP高速缓存表,发现未绑定,则发起ARP请求。这个ARP请求分组封装在数据帧中并且数据帧以广播(数据帧中的目的MAC地址的值是一个广播地址,是48位比特并且值为全1)的形式发送。由于是广播的形式发送,那么所有的主机都会收到这个数据帧,这个时候主机A的IP和MAC地址就会被局域网内所有的主机所缓存起来(这个是一种类似自学习的行为,可以节省网络开销,因为如果只靠请求和响应获取MAC地址,效率是不够高的。)。最后主机B返回一个响应报文给主机A,主机A将得到的MAC地址填入表绑定。这样一来,有了B的MAC地址,A就可以进行封装成帧的操作。

PS:局域网内所有的节点都会执行两个阶段,第一阶段先把收到的发送主机的IP和MAC地址缓存起来,第二阶段才是检查ARP请求的IP地址,符合则响应带自身MAC地址的报文,不符合则不会告诉对方自己的MAC地址。

第二种情况需要跨越路由器:

首先IP分组要发送到D主机,那么一开始会将目的主机与当前掩码值相与,结果发现不能够直接交付,那么查自己的默认网关,将分组发送给默认网关(第一台路由器),这当中的情况是这样的:默认网关地址是下一跳地址,主机A将这个地址给ARP模块,ARP模块查自己的缓存表,发现没绑定,那么发起请求,将下一跳IP地址,源主机IP和MAC地址封装成数据帧以广播的方式去请求第一台路由器的MAC地址,返回的MAC地址和IP分组封装在数据帧中,传输给路由器。(是的,这个过程和不需要跨越路由的传输方式不同,IP模块传给ARP模块的是下一跳IP地址,ARP带着下一跳IP去请求下一跳的MAC。然后最后封装在数据帧中发送出去的IP分组的目的IP是目的主机的IP,这个是不会变的。要区分好。)

R1路由发送分组给R2的情况也是类似的:

目的主机的IP地址和路由表项中的掩码相与(一个查表过程),然后发现是下一跳(可能是网络路由也可能发生默认路由),那么又将下一跳IP地址交给ARP去请求。最终得到的R2的MAC地址,那么分组就发送到R2。最后,R2查表,发现能够找到目的网络,那么直接交付,广播得到目的主机的MAC地址,最后目的主机收到分组。

PS:记住一点,每台路由和所连接的一个主机是一个局域网内,因此每个局域网对数据帧的处理方式就是检查收到的帧中的MAC地址是不是自己的,不是就丢弃。而ARP协议的工作原理是,让局域网中的主机检查收到的ARP分组中IP地址是不是自己的,不是自己的则不回应。

代理ARP:

上图可知,两个网络是包含关系,如果有一个分组从大网络向小网络发送,比如.3向.35发送一个分组,由于发送目的IP与当前掩码相与的结果是等于直接交付的,那么它会直接广播发送ARP请求(这个ARP封装在数据帧中)获取MAC地址。但是实际上.35的网络是要经过路由器的。所以在.3的网络包括路由器在内没有一台主机会响应(因为目的IP都不是自己的),路由器更加不会转发广播地址。所以会失败。

因为目的IP与当前网络掩码相与,得出是下一跳地址,.35会将分组发送给默认网关,那么广播的方式拿到网关的MAC地址,既而发送分组。因此ARP是正常请求成功的。

那么要解决第一类情况,就要用ARP代理。 

R代替返回了R的MAC地址,那么这样分组就可以发送到路由器,由于目的IP是不变的,这样就可以再由路由器进行转发。(也就是代理主要解决的是让分组可以发送到路由器

代理ARP是针对特定的接口才去实现这个代理功能,而不是所有接口。而代理ARP的实现原理就是根据路由器的接口是知道每个网络的大小的,那么目的IP和请求者在不同网络内就需要代理,而同一网络内就不需要。

PS:间接交付,那么第一台路由器就会有响应,如果是直接交付,像上图这种包含情况并且没有代理的情况下,是没有主机(包括路由器)会响应的。

VLAN(虚拟局域网)使用代理ARP非常多。

上图黄色部分就是全1 ,代表数据帧以广播形式发送。

 

 ARP缓存表的查看:

  

ARP缓存表永远认为新的就是正确的,所以当有新的绑定时,会替换掉旧的绑定而不做任何判断,而路由器则会有判断机制来决定要不要把新的替换旧的。

因为ARP缓存表是一种绑定关系,所以只有ARP请求和ARP应答才能够更新ARP缓存表,因为ARP和帧都只在一个物理网内不会跨越网络,它们是成对的绑定关系;而封装IP报文的以太帧中的MAC地址和IP报文中的IP地址不是成对的绑定关系,因为IP报文的IP地址总是不变的,而帧的MAC地址总是在变的,所以除了ARP请求和ARP应答,其余的报文都不能更新ARP缓存表。

ARP一般适用于物理网是局域网并且是以太网,网络层是IP协议的情况。而广域网很少会用广播的方式,因为范围太大用广播通信的开销会非常大,因此ARP不适合广域网,广域网通常会采用点对点通信方式。

RARP:反向地址解析协议。MAC地址--->IP地址

RARP一般用于无盘机器的地址分配,因为没有硬盘(信息在开机是从硬盘读入内存生效),所以配置信息无法预先设置在机器中,因此RARP请求报文中源和目的IP字段是不填的,而源和目的MAC地址都填该无盘机器网卡上的MAC地址;然后收到请求的主机如果是RARP服务器才会发送单播响应。

现在网络基本不用RARP了。因为它只能获得IP地址,只有IP地址只能在局域网通信,现代通信中必须要IP,掩码,网关,DNS4个参数,才能满足网络间的通信。所以后面出现的BOOTP和DHCP协议来替代它。

ICMP协议:

因为IP是无连接的不可靠的传输协议,所以出现差错是不可避免的,那么ICMP作为辅助协议,先发送错误报告,然后才进行更正。

ICMP只会报告给源主机,而且只提供处理建议,而不是处理差错。

ICMP可以用来测试查询,以及做差错报告。

数据链路层所提供的差错检测十分简单,而且只有检错功能,没有纠错功能。IP层本质上又不可靠。差错控制能力,包括检错和纠错主要集中在传输层。

TCP/IP中数据链路层的差错控制只是有根据CRC校验,防止出现传输过程中出现的比特错误之类的问题,不足以向网络层提供可靠服务

可靠交付的功能,数据链路层也有,不过是OSI七层模型中数据链路层的功能,并未在实际中使用。所以,一般保证可靠交付的功能都在传输层来考虑。其实,设计OSI的初衷时,就有在数据链路层实现可靠交付的考虑。不过对于数据传输要求没那么高的服务,可靠交付反而会减小传输效率。

传输层协议之UDP:

真正实现通信的,其实并不是每台主机或者节点设备,而是具体到主机中的某些程序。所以为了使得这些程序之间(在操作系统的层面讲,程序之间的通信叫做进程通信)能够通信,传输层为此而生,传输层负责进程之间的通信将这些应用程序通信的数据交给下层网络操作(包括逻辑网络也就是网络层,物理网络也就是链路层和物理层)来实现。所以传输层的通信不是节点间的点到点通信,而是端到端进程之间的通信。

传输层可以差错控制和流量控制,而IP层没有。

IP地址标识的是主机,而在传输层中,则用端口号来标识通信的进程。所以IP地址和端口在一起作用,标识的是某台主机和主机上运行某个程序(先找到计算机,在找到所运行的程序)。

传输层:将程序源和目的端口封装

IP层:将源和目的主机IP地址封装

链路层:将源和目的MAC地址封装

端口地址有16比特,0~~~1023称为熟知端口(主要是服务器采用),1024~~~49151 称为注册端口,49152~~~65535称为动态端口(每个进程都可以在这个范围动态选取端口来标识,主要是针对临时通信,主要是客户机使用)

UDP报文格式:

上图可以看出UDP的头部只有8个字节,有4个字段,分别是源端口,目的端口,总长度,校验和。UDP封装在IP中,IP的协议字段值为17就是代表UDP。

UDP头部加上数据部分虽然理论上MAX值应该是65535,但是UDP要封装在IP中,而IP的最大长度也是65535,而IP头部占了20字节,因此数据部分65535-20是等于整个UDP报文最大长度,UDP头部占8个字节,那么UDP数据部分MAX长度就是65535-20-8。

 

UDP校验和要检查UDP报文和伪首部,这个伪首部是IP首部部分信息形成,但这个伪首部不会被发送出去。因为UDP报文只有通信的端口号,而缺少了IP地址。所以为了确保正确的主机和正确的端口,必须要从IP头部拿出部分信息(含IP地址)形成伪首部给校验和。校验和还能够可选,因为如果底层网络是个高可靠性的网络,那么在传输层还要进行一次校验,则会有一定开销,这时候不让校验和工作会减少网络开销,因此校验和为可选是有好处的。

PS:虽然在IP层上保证了正确的主机,但OSI各层要独立分工明确,因此UDP校验和也要如此工作。

伪首部使得UDP和IP的界限模糊:

发送的时候:CS校验和字段需要得到源IP地址,而源IP在主机查路由表选路之前是无法得知的,所以必须要在IP层工作后,再回送给传输层,校验和验证了伪首部后,又再向下传给IP层。

同样在接收的时候,数据报经过IP层已经拆解了头部,而送到UDP的时候,又要返回IP层拿回校验信息给校验和验证。

 

虽然UDP和IP通信都是不可靠的,面向报文的,但是因为IP协议只负责主机,而为了满足主机间多目标进程的通信,所以有必要增加传输层中的一个协议UDP。

UDP本身是不面向连接的,所以速度会比面向连接的协议要快。而且有些协议自身带有差错控制和流量控制,那么就不需要传输层再提供,因此也可以使用UDP。

组播和广播因为是有多个接收者,那么面向连接协议也不适合,只能采用UDP。

 

                           

TCP协议:

由于UDP只能传输非常小的数据量,满足不了上层应用需求,而还有上层应用自身的可靠性机制弱,不得不靠下层提供可靠机制,同时IP层也是无连接的,物理网络又有MTU的一个限制,所以在应用和下层网络之间就必须要在传输层设计一个可靠的协议TCP。

TCP是可靠的,为上一层应用也提供了一个统一的投递服务接口,是以是数据流的方式进行,而UDP,IP,ICMP都是以报文的方式进行的。TCP显得特别。因此,TCP地位是十分重要的,它保障了数据传输的可靠性。

PS:TCP是一种逻辑上的连接

TCP是一种有缓冲机制的协议(对上层提供的服务是面向字节流的),这是为了提高传输效率(比如让数据片合成数据块的方式来发送),它的缓冲就是它可以让上一层的应用程序自主选择传输数据的字节单位(也就是让应用程序自行决定发送数据的块数),比如telnet协议的传输就是以最小1字节的数据片来传输的,而文件传输协议就是一大块一大块的传输。

TCP协议软件收到上面发下来的数据后,并不是收多少就马上发多少,而是协议带有一个缓冲区,根据底层网络情况,累计到一定长度才进行发送。这个底层网络情况指的就是下面的物理网络MTU的大小,根据物理网络MTU的情况决定缓冲程度并发送。这种累计到一定程度才进行发送是一种数据的合并。缓冲区的作用是根据底层网络情况合并或者分割上面发下来的数据,其实不仅是发送方,接收方缓冲区也是同样的作用。当上面应用一次性发下来的数据量(字节流)很少,那么TCP协议软件的缓冲就累计才发送,如果送下来的字节流很多,那么缓冲区执行分割,将数据块分割成片,一片片传输。

TCP的推送功能,将缓冲区滞留的数据,可能是没累计满的,也要全部推送,保证可靠投递。

上图中的这些特点都是TCP为了提高数据传输效率而设计的。TCP的可靠投递的特点并不是为了与它的下层对接而设计的,它服务的是上层应用。

TCP全双工通信,同一时刻,两个方向上可以同时传递数据。

 

实际上TCP在进行通信时,不仅会带上要传送的数据,还会携带有确认信息,这种方式称作捎带确认。

总结TCP的可靠通信机制特点:

虽然说可靠与否 与 是否是面向连接的方式并没有必然联系,但面向连接比较容易实现可靠传输机制。

可靠性连接主要表现在两个方面:流量控制和差错控制,滑动窗口协议是流量控制的体现,而捎带确认方式和超时重传是差错控制的体现。

注意:显示确认和捎带确认不同,显示确认是专门发送单独的确认报文(只携带确认信息而不携带要传输的数据信息)。

捎带确认可以减少报文种类(只需要TCP报文就可以解决传输问题,因此TCP报文就会比较复杂)。

TCP也是端到端的,也是要端口的,这里和UDP是一样的,不同的是TCP是面向连接,UDP不是。

 

PS:分组交换的两种方式:以TCP为代表的面向连接的虚电路交换(发送数据前会先建立一条逻辑通道连接),以IP,UDP为代表尽最大努力交付,不面向连接的数据报交换(类似IP分组那样的自由选路机制)。

 

一条TCP连接是端到端的,因此两个端点(主机以及主机进程)的组成:IP地址和进程端口。所以一条TCP连接必须包含源目的的IP地址和端口号,四要素。这四个要素必须一致才能算同一条TCP连接。只要有一个不一样就不算同一条连接。PS:TCP本身只封装了端口号,但是前面提到只有端口号是不行的,是少不了主机地址。参考UDP接收IP层的IP地址。

TCP报文格式:头部和数据部分,对上层面向字节流(而不是像IP,UDP一样的报文流,没有报文,没有边界,但这只是种对上层应用的服务方式),TCP对下层还是属于报文段的形式的也就是有报文格式,报文单位。

上图中第三个字段segment是TCP报文别称,数据段或者报文段。数据段是有边界的,有报文格式,这跟TCP面向字节流好像对不上(字节流无边界,因为不是面向报文所以无报文格式)。

注意:TCP的面向字节流通信只是对上层应用提供通信服务的时候,而不是对下层网络层面向字节流,TCP协议内部在处理上面递交的数据是的时候,无论是接收还是发送,还是按照字节流方式来处理。但是到了网络层,考虑到了传输效率,TCP要将这些字节流合并在一起提高网络层的传输效率,所以送交给网络层的时候以报文段的格式送交,亦或者以报文的形式将网络层的数据取出来,完了以后所有的方式又按照字节流处理。

总而言之,TCP处理数据方式还是在字节流,但是在某些传输环境,要以报文段格式传输。

序号和确认号,作用,进行差错控制,比如报文确认或者重传等,字节为单位,体现面向字节流特征 。

头部长度跟IP报文含义一样,4个字节为单位,因为TCP也有选项,所以头长字段不可少。

6个比特的保留字段

最后的,6个比特的是TCP控制字段,非常重要,每个比特位代表一项TCP协议的操作,包含了连接建立与拆除,滑动窗口机制等全都是由这几个控制字段实现的。

窗口字段,和前面的控制字段一起共同完成流控功能。

  

校验和,内容,作用和UDP一样,计算方式和IP一样,也要校验TCP伪首部(来自部分IP的信息),伪首部报文格式和UDP的完全一样,只不过伪首部的协议字段是TCP。

紧急指针

选项。

控制字段能够标识出来报文类型,流控等,详细见图。

RST:连接复位

SYN:连接建立

FIN:连接终止

ACK:ACK为1表示确认号有效,也表示当前报文携带了确认信息,为0表示报文中不包含确认信息,忽略确认号字段。

PSH:push推操作

PS:任何一种类型的TCP报文都可以使用ACK,比如 针对连接建立请求,可以针对连接终止,可以针对数据传输都可以做ACK。 所有TCP类型的数据除了ACK本身都可以做ACK确认。

上图可知,TCP的发送缓冲区将应用进程发送来的字节流 累计 ,然后根据 底层MTU的 限制将这些数据流分割成数据块或者报文段发送给接收方。接收方收到后,将这些数据块中的字节流又一个个单位地抽取上来。所以,字节流是TCP内部处理方式,它是为应用层服务,但为了提高传输效率 ,所以对下层是以报文段形式发送。

注意:这个长度是指报文是数据部分的长度,不包括 报文头部

所以可见TCP可以满足大量的数据流传递。足足有4G的序号空间,注意不是发送数据空间,下面会提到一次发送数据的MAC值。

序号不连续:序号的关系 可能是这样的,X+L  <  Y+L  <   Z+L

PS:接收时,TCP缓冲区会先将TCP头部去掉,将TCP数据部分抽出来,将数据填入接收缓冲。同样发送端缓冲也是无头部的 。

带外数据也叫紧急数据:

主要作用,将一些紧急或者重要的字符(数据)先发送。位于TCP报文段的数据部分的开始位置 。TCP对带外数据的处理是不会将带外数据也放入缓冲区排队,而是立即执行,直接递交给上层。

紧急指针,表示TCP数据部分中,哪些字节属于带外数据。

 

因为一个TCP报文中,既有带外数据也有普通数据,带外数据的首位可以容易确定,但是末尾需要一个紧急指针才可以确定它和普通数据的边界(也就是明确带外数据部分的结束)。

红色部分是紧急数据,紧急指针指第三个红色部分---带外数据末尾,而蓝色部分是普通数据,紧急指针为0,不指向。

  

可以看到带外数据不参与缓冲区排队,直接递交给上层,而普通数据参与排队,然后则让上层有需要来取。

序号,可以用来确定数据流的顺序,因为底层的IP是不面向连接的,分组会独立自由选路,造成到达的数据是无序的。而TCP需要提供可靠机制保证,所以序号是关键的一环,有了序号字段,可以保证数据流能够按照发送时的顺序排队,让这些零散的无序的字节流块重新正确排列。

TCP的选项字段,面向TCP提供的服务而设计:

 

与IP报文以及报文内容是十分相似的。

下面是选项字段中的介绍:

补充下利用率的概念:利用率分为网络利用率和信道利用率。

网络利用率是网络中所有信道利用率的加权平均。

信道计算公式:发送时延/发送周期

发送周期=发送时延+往返时间   或者   双向传播时延

MSS值太小:会降低网络的利用率,这个利用率从报文开销的角度出发,报文有效部分/报文总长度,因为TCP,IP,帧的头部都是固定的,所以值小意味着有效数据越小,那么报文利用率低,传过去的都是些网络开销,而没有实际意义(因为没有传递到实际数据)

MSS值太大:那么就会导致数据要满足MTU而分片传输,但是IP和底层链路都是不可靠的,所以会导致数据片丢失,由于TCP的可靠传输,导致重传要有网络通信开销,进而降低网络性能。

一个适当的MSS值会提高网络的性能,就是数据长度足够而又不用分片,但受底层不同物理网的MTU影响,很难做到。

所以通常一般在发送时,按照发送方的MTU限制来确定MSS。在通信时,如果接收方不能够处理较长的报文段,那么双方一般会进行MSS协商,确定统一的MSS来互相发送TCP报文段,避免出现MTU差距范围过大,导致一方接收数据要分片。MSS的协商过程,是在TCP建立连接的过程中完成。

窗口比例因子:

指的是TCP发送的数据部分的大小,到底有多少字节。TCP头部中还有个窗口字段,指的就是一次允许TCP报文段发送多少个字节

TCP的窗口字段是16个比特,那么它的窗口大小的MAX值是65535,也就是说TCP最大可发送65535字节的数据,在高吞吐量的环境下,增大窗口大小就是允许TCP报文段携带更多数据一次性发送,在高延迟的环境下,由于发送一次数据所需要等待的时间较长,所以尽可能一次携带的数据量更多较好,这样通过增大窗口大小来解决。

 

窗口缩放因子

窗口缩放在RFC 1072中引入并在RFC 1323中进行了改进。实际上,窗口缩放只是将16位窗口字段扩展为最高32位长度。解决方案是定义TCP选项以指定计数,通过该计数,TCP标头字段应按位移位以产生更大的值。解决16位窗口的TCP不能够应付的场景。

打个比方,假设目前的TCP能发送5840字节,但是窗口缩放因子为7,也就是这时候最大实际窗口为 5840*128(2的7次方)

窗口缩放因子和MSS的建立一样,只能在TCP建立链接过程中指定。而TCP实际窗口大小无论在何时都可以改变。

时间戳,测量往返时间,动态定义超时时间,为后面可靠控制辅助。

TCP可靠特征:流控,差错控制,拥塞控制。

TCP面向连接特征:连接的维护

校验和主要解决的是无差错的问题,确认和重传保证了数据不丢失,不重复,按序。

超时重传的肯定确认机制,对不正确的报文不做确认(所谓的肯定确认,一般的确认分两种,一种是告诉 源 错误消息,一种就是肯定确认,告诉 源 正确地收到数据),要求发送方重传。

在一段时间内,发送方没有收到接受方确认的报文信息(向源回送的ACK报文),就认为当前数据是错误传递的,需要重传。

采用累计确认机制,告诉源,到底有哪些数据是正确接收的。

因为网络的能力始终是有限的,有可能确认报文会因为拥挤的网络无法及时到达,那么就需要重传机制。

未确认的数据分两种:因网络能力导致未收到确认信息的(实际上是正确收到了,但确认报文滞留在网络中),另一种是不正确投递的报文,该报文不完整,或者直接丢失在网络中。

上个图可知,比如,当前计算机发送TCP报文段,从1201开始,长度为200,那么TCP的累计确认,累计了400,那么期望确认号为1601,这里得知,期望确认号等于下一次发送TCP报文段的序号。而前面1401和1201的TCP报文段由于收到了确认ACK,这两个超时定时器就会删除,不用进入重传机制。

第三个报文段是出错的,接受方必然不会发送确认报文,那么第三个定时器超时后发起重传,并且定时器的值置为初始值。如果第三段报文收到确认后,那么定时器删除,表示重传成功。

丢失报文和受损报文是才差不多的过程 :

 

最后一种情况是丢失确认报文:

这种情况有两个情景,如果前两段报文都发送成功,但由于网络原因,确认报文滞留在网络中,而定时器时间还很充裕,一直收到了第三段确认报文都没失效。此时看起来,接收方的确认报文只针对第三段报文发送,但由于tcp的累计确认机制,说明第三段以前的所有报文都正确收到了,那么之前和当前的定时器全部删除;剩下的一种情景就是第一段和第二段的确认报文在定时器时间到了还没收到,那么定时器初始化,开始重传。所以采用累计确认和重传机制就可以保证上述场景。

这个问题的场景一是:主机一的第一段报文已经被确认,但是由于网络原因确认报文滞留在网络中导致超过定时器时间,主机一又重新发送第一段报文,所以主机二收到重复的报文段。

场景二:同样也是报文段被确认,但是定时器设置较短,即使确认报文能够到达也超过时间。

所以RTT(报文往返时间)的设置非常关键。如果RTT设置的合适,那么就会减少网络中的重复报文,如果设置的太小,会增加网络的重复报文。

自适应超时重传算法,根据当前的RTT值来调整下一次的定时器值。但要注意一点,RTT的改善只能解决上面所述的场景二对定时器有效,但如果是确认报文丢失是没办法生效的,因为一旦确认报文丢失,只能根据重传机制(报文没有能够到达,也就没办法得知往返时间RTT)。

动态调整RTT时间能够很好提升TCP传输效率。

上图描述的是停止等待协议。但停止等待协议并不适合实际。

因为所有接收来的数据都会放在接收缓冲区内部,因此一旦接收缓冲区饱满,没能力再接收,那么后面接收的数据只能丢弃。----被数据流淹没。

一旦数据被丢弃,让发送方没收到确认,导致发送方又重传,结果造成数据堆积在网络中,让网络变得拥挤。

拥塞主要分两种,接收方和网络的拥塞。接收方的拥塞可以通过TCP的流控来解决,但是网络的拥塞TCP解决不了,那么尽可能降低拥塞的可能就是尽量少发报文。

也就是说滑窗机制能够进行拥塞控制和流控。

实际上滑动窗口机制,是根据当前接收情况来调整发送方的发送滑动窗口大小(即为发送方一次所能发送的数据量)。TCP拥塞机制其实就是一种拥塞避免的措施。就是说当网络拥挤度比较低的时候,TCP的拥塞机制可以减轻这种情况而不是消除,如果网络十分拥挤的时候,就没有作用。

注意一点:其他协议也会使用滑动窗口协议,那么由于TCP是面向数据流的,所以单位是字节流,而其它报文是报文流,所以单位是报文段。滑窗协议不是TCP特有的。

窗口不等于缓冲区(窗口大小不等于缓冲区大小),窗口是缓冲区的子集(一部分)。

 

图中可知:当发送方收到确认号4号,那么滑动窗口才会将之前的字节删除,然后滑动窗口继续向前滑动。如果没有收到确认,滑动窗口则继续保留前面的字节(可能会进行重传)。

从滑动窗口协议本身来看,体现的只是一种发送和确认的关系也就是确认机制,并不怎么体现流控。但在TCP中,对滑动窗口 改进 。TCP的滑动窗口主要针对发送方,所以也叫做发送窗口,,因为接收方只要缓冲区足够的话,就不存在窗口问题。

 

发送窗口是缓冲区的部分,发送窗口的内容和应用程序是送下来的字节没有必然的关联,因为如果应用送下来1个字节,那么缓冲区就发送1个,如果上面送下来大量数据,那么就要按照滑动窗口大小来发送。

 

上图中,已发送已收确认的字节段会被删除。

接受缓冲区没有窗口的概念:

上层程序对字节的接收和TCP的收发没有什么必然联系。上面程序可以以任意速率接收或者下送,而TCP也可以以自己的速率来收发数据。

体现TCP封装在IP当中,IP的独立选路导致会出现零散段。

 

要实现流控,就是将滑动窗口改进成动态可变。这就是TCP的窗口特点。如果接收方接受能力强,证明可用缓冲区还比较多,那么发送窗口值可以大一些。接收能力弱,可用缓冲区比较少,那么发送方的窗口值要小些。所以发送窗口大小是根据接收方决定的。

TCP的首部中有一个比特位是窗口字段,这个窗口字段并不是指发送方窗口值,而是接收方告知发送方,接收方可用缓冲区大小的通告值。极端情况下,通告值为0,发送方不能再进行发送,因为接收方收不了数据,多余的数据只会丢弃。接收方上面的应用会继续从接受缓冲区接收数据,等接收方缓冲区腾出空位,发送方才可以重新开始发送。

当网络原因使得窗口值通告遗失在网络中的时候,避免出现发送方等待 接收方缓冲区可用,而接收方又等待发送方发送数据,造成的死锁,采用试探性发送就可以避免这种情况。

带外数据由于不需要在缓冲区排队,可以直接被应用接收。

因为滑动窗口是可变的,某时刻有数据要重传,但该时刻滑动窗口的大小和先前不一样,会导致重传的数据可能是之前的一部分或者比先前的还多一部分。

序号是恢复顺序非常关键的一环。

由于网络原因(网络节点处理速度不一样),窗口改变机制可能会发生时延才生效。

TCP端到端的特性,只能考虑到发送方和接收方,没办法考录网络中 的拥塞。

上两图可知,当接收方满时,确认报文中,窗口值为0。当接受方腾出一点空间时候,又会发送一个确认报文窗口值为1000,也就是发送方 可以发送的数据部分长度

一旦出现报文丢失,意味着网络拥塞,那么就要降低发送速率和发送的流量,流量中有部分是重传的数据流量,一部分是有效数据流量。

有效数据流量根据拥塞窗口决定。重传流量根据超时时限决定。

还有一点,就是重传定时器的值也要做相应的调整,因为网络堵塞会有较高时延,时延高意味着RTT高,既而会影响到重传定时器。

所以TCP拥塞控制,一要降低数据流量,二要降低重传流量。一旦出现重传,会很影响网络性能。

 当网络拥塞得到一些缓解的时候,TCP就要恢复或者说提高一些发送流量,提高传输效率。这时候采用慢启动。慢启动提高的发送流量是一个缓慢的过程,比如说MSS值为1,那么收到下一次确认后提高为2,依次递增,是一个比较缓慢的过程。 

TCP有流控和拥塞控制,发送窗口值由窗口通告来决定只是一个端到端的过程,而拥塞控制是一个中间过程,因为中间代表的是网络的堵塞情况。所以,TCP发送窗口还要取决于一个拥塞窗口变量(取拥塞窗口和窗口通告值两者之间的最小值),拥塞窗口是一个表示网络堵塞 情况的一个状态变量由TCP维护。

比如说(窗口通告值为80)当拥塞窗口为7的时候,只收到了来自4的确认,这个时候MSS还会继续加1,但是如果到了拥塞窗口为40也就是发送窗口等于窗口通告的一半,这个时候MSS就不会继续再增加,必须等前面所有报文的确认都收到了,滑动窗口再继续滑动,MSS再增加1(这样的做法可以使得网络处于一定的空闲,缓解堵塞情况)这时候的慢启动更加的慢。下面是慢启动的速率图:

 

上图是慢启动和快速递减的时间图,可以看到慢启动的过程比较缓慢,一旦发生数据丢弃(一旦发生错误会导致重传使得网络变慢),就会开始快速递减。

因为发送方和接收方的各自的应用进程都是以自己的工作速率从各自缓冲区取数据,当接收方从有10个字节点缓冲区一次只取了一个字节,那么接收方缓冲区就只腾出了一个位置,那么返回的确认报文携带的窗口通告值只为1,使得发送方只能以较小的数据量发送,有效数据量太少,导致网络利用率低(报文有效数据和整个报文的比值),协议报文开销大,产生严重性能问题。

综上所述:糊涂窗口的原因就是收发主机各自的应用程序速度不匹配导致的。

解决方法:

使得接受缓冲区有足够空间的时候才选择发送窗口通告值(在此前通告窗口值维持为0)

推迟确认,一旦推迟确认,那么RTT值就会高,RTT值高导致重传定时器时间设定就会长,那么发送方的发送速率也会降低(没收到确认,就没有收到接收方的通告,窗口的数据一旦发送完毕,窗口是不能滑动的,那么新的字节数据也不能发送)。所以推迟确认来达到减缓发送也可以解决糊涂窗口这种情况。

或者使用捎带确认的方式,TCP是全双工的通信,一个主机既是发送方也是接收方,当目的主机要返回确认报文的同时也可以发送报文,所以在要发送报文的时候捎带上确认。(TCP报文的特性可以使用捎带)

当定时器的时限快到的时候,因为要避免重传,所以也要发送确认。(意思就是尽量让确认报文迟一点再发,因为迟一点,接收方缓冲的空间就会多一点)

注意:发送方发送的数据不一定是窗口大小,窗口内的数据可以分成多块连续发送。 

下面是发送方的角度:

发送方不一定马上要发送窗口数据,而是延迟,等到通告值足够大或者说足够合理的时候再发送。

延迟时间会导致的问题,过长会导致一些实时性交互应用反应变慢,比如电话应用,延迟时间短,那么发送的数据量也就是少(因为接收方缓冲没有腾出很多空间)

所以具体的延迟策略是根据网络性能决定的。

每一条TCP连接,缓冲区状态的维护,都要占用大量内存,受限于内存。所以在多台主机相互间的TCP通信中,每一台机器最多只能有65535个TCP连接存在。

上图可知,一个端口可以被多条TCP连接共享(主要发生在客户服务器模型中)。

TCP可以允许两个通信实体同时发起主动连接,任何一个主机可以作为TCP接收方也可以作为发送方即主动发起的一方。

 

初始序号,建立连接起,发送的第一个字节的序号(不是每个报文段的第一个字节),TCP通信双方都要知道这个初始序号才可以开始正常通信(这涉及到排序,如果没有初始序号,一旦接收到无序的数据,就不知道接收的数据流在整体中的位置,就无法作出判断保证有序,接收方重排的功能就无法实现)。这个序号是随机的,不固定。

三次握手第一阶段:客户方主动发起TCP请求,TCP报文段SYN字段值为1,表示当前TCP报文段是连接建立的请求类型,这时候初始序号seq 随机生成,ack确认号比特是0(并且ack是无效的),因为这个阶段没收到任何确认报文,而且TCP数据部分是没有的,因为连接没建立无法发送数据,因此这个时候发送的是TCP头;TCP头部的6个控制比特除了SYN为1 ,其它比特都是0。

三次握手第二阶段:服务器方收到连接建立请求后,如果同意建立连接,那么就会给出确认,这个确认号值就是下一次的序号或者初始序号值+1,ACK控制比特值置为1说明这个确认号是有效的,由于TCP是全双工的,所以服务方也必须发起对客户方的TCP连接建立请求,在第二阶段,虽然服务方同意建立连接,但服务方的数据还不能发给客户方,服务方只能发确认报文给客户方,因此服务方也要跟客户方建立连接(是的,不管是服务方还是客户方,它们同时既是接收者也是发送者,第二阶段是客户方能够向服务方发数据,服务方只能向客户方发   确认报文,因此在此阶段,服务方还要向客户方请求,能够让服务方也能向客户方发数据),体现在SYN控制字段和第一阶段一样都是1,并且服务方有自己的初始序号seq。

三次握手第三阶段:收到了服务方的连接建立请求,客户方也返回确认报文给服务方,ACK控制字段为1,SYN则不再生效为0,客户方seq为第二阶段返回的确认号,ack值为服务方的确认号或者说服务方下一次的序号。

TCP三次握手完成了初始序号的通知和双向连接的建立。

通常来讲,三个阶段都是TCP的头部而没有数据部分,但在第三阶段,如果客户有数据发送,也可以在这个阶段携带数据发送。

在这个连接建立的过程中,MSS和窗口缩放因子的协商也是在该过程中完成。

TCP通信的建立是双方同时双向建立的,而拆除有点不同,是单向拆除,拆除自己的连接,并且每次拆一个,因为网络的缓冲能力使得分组可能会迟些到达,一旦一次全部拆除可能会导致后面数据收不到。

由于TCP是封装在IP中的,IP不可靠,独立选路,所以不管是什么类型的TCP报文(建立,拆除等)都有可能发生丢失或者出错,所以TCP的流控和差错控制是任何时候(连接建立,数据发送,连接拆除)都起作用。

差错和流控发生在TCP整个传输过程当中,而不仅仅发生在数据传输部分。

TCP的连接分两步,每一步建立一个方向上的,而拆除有点类似。连接和拆除都只能是自己方向上的。由于TCP的可靠机制保障,使得TCP某方向上的连接被拆除后不能发送数据,但可以发送确认,因为对方连接可能还没有拆除,一旦有数据正在发送而得不到响应会导致错误后果。

当客户方要求结束TCP连接时,第一阶段:会将首部中控制位FIN置为1,序号seq是承接上一次发送完的序号,ack确认号可以是对服务方上一次发送的数据的捎带确认(图中举的例子是主机初始化状态)。

捎带确认可提高传输效率

第二阶段:服务方同意,ACK字段置为1,确认号ack生效,seq值一样是承接服务方上一次发送的数据(只要初始序号确立,就会一直顺序下来直到连接彻底释放)。

第三和第四阶段其实和第一,第二阶段是一样的,这个时候是释放服务方的连接。

可以看到,4次握手和3次握手有相似的地方,不同的是中间的服务方请求,连接建立的时候是相当于把两段报文 (服务方对客户方确认和服务方请求)和为一段,而4次握手要分开。

4次握手中间的这两次报文不能合并,因为在客户方主机拆除连接的时候,服务方还可以向客户方发数据,客户方必须响应,如果中间的两段报文合并会导致服务方也要马上关闭,不合要求。

而3次握手是连接建立的时候,在双向连接没有建立之前,是不能发送数据的,因此3次握手(服务方对客户方确认和服务方请求)可以合为一段;而4次握手本身是处于连接建立的基础上,所以中间的两段报文是 一定不能合并。

复位,恢复TCP连接成最初始的情况。TCP最初始的状态是根本没有建立TCP连接。所以复位也类似TCP连接拆除,但又不太一样,因为正常的拆除是该收到的数据收完,该发送的发完,最后才释放,而复位是强制拆除,立即终止连接,这样就有可能会丢失数据。

异常状态下,可能就会使用复位。

复位的过程:发出RST为1的报文的一方直接中断,收到的一方也直接中断。

TCP有限状态机:先跳过,后续补充。

猜你喜欢

转载自blog.csdn.net/qq_37391017/article/details/86554484
今日推荐