IM即时通讯-理论篇之通信协议

概述

即时通讯(Instant Messaging,简称IM)是一个实时通信系统,允许两人或多人使用网络实时的传递文字消息、文件、语音与视频进行交流。目前随着互联网的广泛普及,QQ、微信之类的即时通讯软件已经融入大家的生活与工作的方方面面。而市面上流行的软件为了方便用户之间即时沟通,也都集成有IM的功能。

本系列文章旨在系统性地整理和介绍即时通讯领域方面的理论和实现,本文为理论篇的第一篇文章,介绍其底层的通信协议。

TCP/IP协议栈

image.png

TCP/IP协议栈是一系列网络协议的总和,构成了网络通信的核心骨架,是现代互联网通信的基石。TCP/IP协议栈屏蔽了不同硬件和操作系统的差异,定义了网络通信过程中的约束和规范,设备或软件只需要符合相应的标准即可接入。

TCP/IP协议采用通用的分层结构,共四层结构,分别是应用层、传输层、网络层和链路层,每层协议都包含多个相应的协议。应用层数据从发送方最终到接收方的整个过程中,上层向下层传输会依次封装相应的协议首部,相应地,下层向上层传输会依次去掉协议首部。协议首部定义了该层协议处理所需要的元数据信息,体现了协议规范的全部细节。

image.png

举一个示例,当通过http发起一个请求时,应用层、传输层、网络层和链路层的相关协议依次对该请求进行包装并携带对应的首部,最终在链路层生成以太网数据包,以太网数据包通过物理介质传输给对方主机,对方接收到数据包以后,然后再一层一层采用对应的协议进行拆包,最后把应用层数据交给应用程序处理。

将网络通信比作送快递的话,商品外面的一层层包裹可以理解为各层协议的首部封装,包含了商品信息、收货地址、收件人、联系方式等信息。

另外快递要送到用户手中,还需要配送车、配送站、快递员之间的相互配合。配送车就是物理介质,配送站就是网关, 快递员就是路由器,收货地址就是IP地址,联系方式就是MAC地址。
 
配送车将商品从仓库运送到附近的配送站,配送站根据收获地址里的省市区,确认是否需要继续转发到其他配送站,当包裹到达了目标配送站以后,快递员通过联系方式找到收件人,最终将商品交给用户。  

链路层

链路层位于四层协议的最底层,直接跟物理介质打交到。

物理介质就是把电脑连接起来的物理手段,常见的有光纤、双绞线,以及无线电波,它决定了电信号(0和1)的传输方式,物理介质的不同决定了电信号的传输带宽、速率、传输距离以及抗干扰性等等。TCP/IP支持多种不同的链路层协议,这取决于网络所使用的硬件,如以太网、令牌环网、FDDI(光纤分布式数据接口)及RS-232串行线路等。

在TCP/IP协议族中,链路层主要功能是为上层提供数据报的发送和接收。不管具体的链路层协议,需要解决以下三个共同的问题:封装成帧、透明传输、差错检测。

封装成帧

网络通信就是把有特定意义的数据通过物理介质传送给对方,单纯的发送 0 和 1 是没有意义的,要传输有意义的数据,就需要以字节为单位对 0 和 1 进行分组,并且要标识好每一组电信号的信息特征,然后按照分组的顺序依次发送。封装成帧(framing)就是在一段数据的前后分别添加首部和尾部,这样就构成了一个帧。接收端在收到物理层上交的比特流后,就能根据首部和尾部的标记,从收到的比特流中识别帧的开始和结束。

以以太网(Ethernet II)为例,整个数据帧由首部、数据和尾部三部分组成,首部固定为14个字节,包含了目标MAC地址、源MAC地址和类型;数据最短为46个字节,最长为1500个字节,如果需要传输的数据很长,就必须分割成多个帧进行发送(上层协议处理);尾部固定为4个字节,表示数据帧校验序列,用于确定数据包在传输过程中是否损坏。

Preamble Start frame delimiter MAC destination MAC source 802.1Q tag (optional) Ethertype Payload Frame check sequence (32‑bit CRC) Interpacket gap
7 octets 1 octet 6 octets 6 octets (4 octets) 2 octets 46‑1500 octets 4 octets 12 octets

以太网通过MAC地址来唯一标识网络设备,并且实现局域网上网络设备之间的通信。MAC地址也叫物理地址,大多数网卡厂商把MAC地址烧入了网卡的ROM中。发送端使用接收端的MAC地址作为目的地址。以太帧封装完成后会通过物理层转换成比特流在物理介质上传输。

主机收到数据帧时,会检查帧头中的目的MAC地址,如果目的MAC地址不是本机MAC地址,也不是本机侦听的组播或广播MAC地址,则主机会丢弃收到的帧。如果目的MAC地址是本机MAC地址,则接收该帧,检查帧校验序列(FCS)字段,并与本机计算的值对比来确定帧在传输过程中是否保持了完整性。如果检查通过,就会剥离帧头和帧尾,然后根据帧头中的Type字段来决定把数据发送到对应的上层协议进行后续处理。

透明传输

由于帧的开始和结束的标记是使用专门指明的控制字符,因此,所传输的数据中的任何8比特的组合一定不允许和用作帧定界的控制字符的比特编码一样,否则就会出现帧定界的错误。而透明传输的意义在于上层协议发送的数据不应该受到帧定界的影响。

为了解决这个问题,常见的方案是字节填充。具体的方法是:发送端的数据链路层在数据中出现控制字符的前面插入一个转义字符。而在接收端的数据链路层在把数据送往网络层之前删除这个插入的转义字符。

以太网在传送帧时,各帧之间还必须有一定的间隙。因此,接收端只要找到帧开始定界符,其后面的连续到达的比特流就都属于同一个MAC帧。可见以太网不需要使用帧结束定界符,也不需要使用字节填充来保证透明传输。

差错控制

现实的通信链路都不会是理想的。这就是说,比特在传输过程中可能会产生差错:1可能会变成0,而0也可能变成1,这就叫做比特差错。目前在数据链路层广泛使用了循环冗余检验CRC (Cyclic Redundancy Check)的检错技术。
i
“无比特差错”与“无传输差错”并不是同样的概念。在数据链路层使用CRC检验,能够实现无比特差错的传输,但这还不是可靠传输。像帧丢失、帧重复或帧失序这类的问题,需要更上层的协议来处理,比如TCP。对于通信质量良好的有线传输链路,数据链路层协议不使用确认和重传机制,由上层进行处理,反而能在一定程度上提高网络的通信效率。

MTU最大传输单元

最大传输单元(Maximum Transmission Unit),即MTU,为数据链路层的最大载荷上限(即IP数据报最大长度)。每段链路的MTU可能都不相同,一条端到端路径的MTU由这条路径上MTU最小的那段链路的MTU决定。如果上层发送的数据大于该长度,则需要上层自己进行分片处理,否则会被链路层协议丢弃。

一个IP数据报在以太网中传输,如果它的长度大于当前链路MTU值(通常为1500),就要进行分片传输(这里指IP层分片),使得每片数据报的长度都不超过MTU。分片传输的IP数据报不一定按序到达,但IP首部中的信息能让这些数据报片按序组装。

不懂就问

数据帧的MAC地址是如何设置的?会发生变化吗?

image.png

主机发送的数据,在网络层会封装源Ip和目标IP,在链路层会封装源MAC和目标MAC地址。当IP网络层通过目标IP确定下一条路由IP时,就会通过ARP地址解析议获取路由IP的MAC地址,并更改为数据帧的目标MAC地址。也就说当数据帧在IP网络层及以上的设备间发生传递时,源MAC和目标MAC地址会发生相应的变化。

image.png

如何确定以太网数据帧的上层协议?

以太网帧中包含一个Type字段,表示帧中的数据应该发送到上层哪个协议处理。比如,IP协议对应的Type值为0x0800,ARP协议对应的Type值为0x0806。

如何获取路径最大MTU,避免上层分片

IP数据报分片会增加处理开销和空间开销,如何才能避免分片呢?
源地址将数据报的标志位设为DF(Don’t Fragment,不要分片),再逐渐增大发送的数据报的大小。路径上任何需要将报文进行分片的设备都会将这种数据报丢弃并返回一个”数据报过大”的ICMP响应到源地址。这样,源主机就”学习”到了不用进行分片就能通过这条路径的最大的最大传输单元了。

然而不幸的是,ICMP可能会被防火墙或路由器的访问控制列表给拒绝了。如果你可以管理并配置这些设备,只要允许ICMP(Type=3, Code=4)的消息可以通过即可,否则只有关闭路径MTU发现功能,因为至少分片还能通信,而避免分片则彻底无法通信了。

集线器、交换机、路由器的区别?

设备 用途 特点
集线器 将多条以太网双绞线或光纤集合连接在同一段物理介质下,主要功能是对接收到的信号进行再生整形放大,以扩大网络的传输距离,同时把所有节点集中在以它为中心的节点上 工作在物理层,共享带宽,无法隔离冲突域,只能以半双工方式
交换机 连接局域网内的设备,内部维护MAC地址与端口的映射表,将相应目标MAC地址转发到对应的设备。相比基线器、中继器和网桥,交换机还提供了更先进的功能,如虚拟局域网(VLAN)和更高的性能,常用于组建大型局域网 一般工作在链路层,独享带宽,隔离冲突域,以全双工方式
路由器 一种连接多个网络或网段的网络设备,它能将不同网络、网段或VLAN之间的数据信息进行“翻译”,以使它们能够相互“读”懂对方的数据,从而构成一个更大的网络 工作在网络层,虽然通过IP地址进行网络路由,但需要转换成MAC地址在链路层转发

不过目前用于组件中大型局域网的商用交换机一般都可以工作网络层。

网络层

链路层提供是局域网内的通信能力,而网络层提供的是主机到主机的通信能力,跨域多个网络。对于上层发送的数据,网络层根据需要会进行分组转发,每一个分组(也就是IP数据报)独立发送,与其前后的分组无关(不进行编号)。当所有分组到目的主机时,才进行分组合并,并最终交付上层。

但网络层向上只提供简单灵活的、无连接的、尽最大努力交付的数据报服务。网络层不提供服务质量的承诺。也就是说,所传送的分组可能出错、丢失、重复和失序(即不按序到达终点),当然也不保证分组交付的时限。

image.png

协议的格式中主要的字段:

  • 标识:用于唯一标记一份数据报,当数据报被分片时,各个分片标识相同,用于重组分片
  • 标志:最低位WF=1时表示还有分片;中间为DF=1表示不能分片
  • 片偏移:分片后的分组相对于原数据报的位相对置
  • 生存时间:数据报能在因特网中经过的路由器的最大数值(跳数)
  • 协议:数据报携带的数据是使用何种协议,以便使目的主机的IP层知道应将数据部分上交给哪个处理过程
  • 源地址和目的地址:发送方和接收方的IP地址

IP地址

image.png

IP地址是网络层最终的概念,表示的是网络层设备进行通信的唯一标识。由于IP地址的结构需要能够方便的网络的寻址,IP地址的编址方法共经过了三个阶段:分类的IP地址、划分子网、无分类编址CIDR。

分类的IP地址

分类的IP地址就是将IP地址划分为若干个固定类,每一类地址都由两个固定长度的字段组成。其中第一个字段是网络号(net-id),它标志主机(或路由器)所连接到的网络。一个网络号在整个因特网范围内必须是唯一的。第二个字段是主机号(host-id),它标志该主机(或路由器),一个主机号在它前面的网络号所指明的网络范围内必须是唯一的。

image.png

划分子网

image.png

由于分类IP这种固定式的划分子网,使得IP地址的分配不够灵活,造成的利用率不高。划分子网就是通过将一个网络划分成多个子网,对于外部来说还是一个网络。划分子网后IP地址变成了三级结构。划分子网只是把IP地址的主机号这部分进行再划分,而不改变IP地址原来的网络号。

image.png

我们知道,从IP数据报的首部无法看出源主机或目的主机所连接的网络是否进行了子网的划分。这是因为32位的IP地址本身以及数据报的首部都没有包含任何有关子网划分的信息。因此必须另外想办法,这就是使用子网掩码(subnet mask)。

路由器在和相邻路由器交换路由信息时,必须把自己所在网络(或子网)的子网掩码告诉相邻路由器。在路由器的路由表中的每一个项目,除了要给出目的网络地址外,还必须同时给出该网络的子网掩码。

无分类编址CIDR

CIDR消除了传统的A类、B类和C类地址以及划分子网的概念,因而可以更加有效地分配IPv4的地址空间。CIDR把32位的IP地址划分为两个部分。前面的部分是“网络前缀”(network-prefix)(或简称为“前缀”),用来指明网络,后面的部分则用来指明主机。

CIDR把网络前缀都相同的连续的IP地址组成一个“CIDR地址块”。我们只要知道CIDR地址块中的任何一个地址,就可以知道这个地址块的起始地址(即最小地址)和最大地址,以及地址块中的地址数。

分配到一个CIDR地址块的单位,仍然可以在本单位内根据需要划分出一些子网。这些子网也都只有一个网络前缀和一个主机号字段,但子网的网络前缀比整个单位的网络前缀要长些。为了更方便地进行路由选择,CIDR使用32位的地址掩码(address mask)。地址掩码由一串1和一串0组成,而1的个数就是网络前缀的长度。

由于一个CIDR地址块中有很多地址,所以在路由表中就利用CIDR地址块来查找目的网络。这种地址的聚合常称为路由聚合(route aggregation),它使得路由表中的一个项目可以表示原来传统分类地址的很多个(例如上千个)路由。路由聚合也称为构成超网(supernetting)。

在使用CIDR时,由于采用了网络前缀这种记法,IP地址由网络前缀和主机号这两个部分组成,因此在路由表中的项目也要有相应的改变。这时,每个项目由“网络前缀”和“下一跳地址”组成。但是在查找路由表时可能会得到不止一个匹配结果。这样就带来一个问题:我们应当从这些匹配结果中选择哪一条路由呢?正确的答案是:应当从匹配结果中选择具有最长网络前缀的路由。这叫作最长前缀匹配(longest-prefix matching),这是因为网络前缀越长,其地址块就越小,因而路由就越具体(more specific)。

公网IP与内网IP

由于IP地址的紧缺,一个机构能够申请到的IP地址数往往远小于本机构所拥有的主机数。考虑到因特网并不很安全,一个机构内也并不需要把所有的主机接入到外部的因特网。因为很多实际场景,比如大型商场或者酒店用于营业和管理的计算机是不需要与外部网络相连。

对于这些仅在机构内部使用的计算机就可以由本机构自行分配其IP地址。这就是说,让这些计算机使用仅在本机构有效的IP地址(这种地址称为本地地址/内网IP),而不需要向因特网的管理机构申请全球唯一的IP地址(这种地址称为全球地址/公网IP)。这样就可以大大节约宝贵的全球IP地址资源。

如果任意选择一些IP地址作为本机构内部使用的本地地址,那么在某种情况下可能会引起一些麻烦。例如,有时机构内部的某个主机需要和因特网连接,那么这种仅在内部使用的本地地址就有可能和因特网中某个IP地址重合,这样就会出现地址的二义性问题。

为了解决这一问题,RFC 1918指明了一些专用地址(private address)。这些地址只能用于一个机构的内部通信,而不能用于和因特网上的主机通信。换言之,专用地址只能用作本地地址而不能用作全球地址。在因特网中的所有路由器,对目的地址是专用地址的数据报一律不进行转发。以下三类IP为内网IP:

  1. 10.0.0.0到10.255.255.255 (或记为10.0.0.0/8,它又称为24位块)
  2. 172.16.0.0到172.31.255.255 (或记为172.16.0.0/12,它又称为20位块)
  3. 192.168.0.0到192.168.255.255 (或记为192.168.0.0/16,它又称为16位块)

分片与重组

IP数据报在网络上传输时,要经过多个物理网络才能抵达目的地。不同的网络由于链路层和介质的物理特性不同,所以传输时,对数据帧的最大长度都有一个限制,这个限制就是最大传输单元MTU。IP协议规定,在因特网中所有的主机和路由器,必须能够接受长度不超过576字节的数据报。

如果上层发送的数据经由IP层封装后的数据报超过了MTU,则IP层就会进行分片。当然分片不一定只发生在发送端,中间网络也有可能发生分片,但是重组是在接收端进行的。

image.png

分好片的IP数据抵达目的主机,目标主机对各分片进行重组,恢复成分片之前的数据报。分片重组依赖IP数据报的首部字段,具体如下:

  1. 根据“标识”字段确定收到的分片属于原来哪个IP数据报;
  2. 根据“标志”字段的“片未完MF”子字段可以确定分片是不是最后一个分片;
  3. 根据“偏移量”字段可以确定分片在原数据报中的位置。

路由选择

我们知道源主机和目标主机可能会跨越多个网络,如何找到一条通往目的主机的路径,如果存在多条路径的话,怎么找到一条最优的呢?这就是路由选择协议问题。

image.png

路由选择协议分两种,一种是大型网络内部各子网的路由选择(域内路由选择),一种是外部网络间的路由选择(域间路由选择)。常见的域内路由选择协议有RIP和OSPF,常见的域间路由选择协议有BGP。

路由选择协议大致原理:路由器与相邻路由器不断交换当前的链路状态,并更新路由器本身的链路状态,最终快速实现达到路由信息的同步。

不懂就问

IP地址与MAC地址的关系

IP地址与MAC地址使用的层次不同,IP地址是网络层及以上使用的,MAC地址是链路层及以下使用。
IP地址用于唯一标识网络中一台主机或路由器;而MAC地址是用于标识局域网内工作在链路层的设备。
IP数据报最终要想在链路层转发,需要将下一条跳的IP地址转换为MAC地址,而这一过程是由网络层ARP协议处理的,上层只需要关心逻辑上的IP地址,而不用关心物理的MAC地址。

IP数据报源IP和目标IP会变化吗

IP数据报源IP和目标IP都有可能发生变化。

我们知道对于位于内网的主机要想与外部网络通信,需要配置公网IP。由于公网IP资源有限,目前常用的方案是通过NAT网络地址转换,内网主机与NAT网关通信,NAT网关更新IP数据报的源IP为公网IP。

image.png

在负载均衡NAT模式下,IP数据报的目标IP会改变成真实服务器的IP,但同时负载均衡器需要作为真实服务器的NAT网关,来保证请求和响应的IP地址是一致的。

IP地址需要手动配置吗

IP配置分两种,一种是静态IP配置,另一种是动态IP配置。静态IP配置的缺点是需要了解当前网络的情况,对于使用方不友好,一般网管使用较多。常见的是动态IP配置,主机通过DHCP协议与DHCP服务器交互,来获取IP进行配置。获取到的IP一般是有时效限制的,称之为租约,租约内IP一直是可以使用的。

传输层

image.png

IP层提供主机到主机的通信能力,但是真正的发送方和接收方是主机上运行的进程(应用程序)。因而传输层提供的应用进程间的通信能力,通过端口号标识两端的应用程序进程。因为IP层提供的不可靠的数据转发服务,对于运输层来说有两种选择:一是提供有序、可靠的数据传输服务,另一种是跟IP层一样尽最大能力交付,由更上层的应用层来根据情况来处理。

UDP协议

UDP跟IP层一样尽最大能力交付,即不保证可靠交付。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。

应用程序必须选择合适大小的报文。若报文太长,UDP把它交给IP层后,IP层在传送时可能要进行分片,这会降低IP层的效率。反之,若报文太短,UDP把它交给IP层后,会使IP数据报的首部的相对长度太大,这也降低了IP层的效率。因此UDP的报文首部是非常简单的,只有源端口、目的端口、长度和校验和四个字段,共8各字节。

image.png

TCP协议

TCP是面向连接的传输层协议,提供的是一种可靠传输服务,通过TCP连接传送的数据,无差错、不丢失、不重复、并且按序到达。

image.png

另外TCP是面向字节流的。TCP中的“流”(stream)指的是流入到进程或从进程流出的字节序列。“面向字节流”的含义是:虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序交下来的数据看成仅仅是一连串的无结构的字节流。

TCP不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系(例如,发送方应用程序交给发送方的TCP共10个数据块,但接收方的TCP可能只用了4个数据块就把收到的字节流交付上层的应用程序)。但接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。当然,接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据。

协议格式

image.png

首部固定部分各字段的含义如下:

  • 源端口和目的端口:用于标识发送端和接收端的应用程序进程
  • 序号:序号范围是0到[2的32次方-1],超过最大值下一个序号就又回到0。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。
  • 确认号:期望收到对方下一个报文段的第一个数据字节的序号。B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节(序号501~700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701
  • 数据偏移:它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。这个字段实际上是指出TCP报文段的首部长度。
  • 控制位:同步SYN(表明是连接请求报文段,用于同步序号);确认ACK(用于报文段收到确认);终止FIN(表示此报文的发送方的数据已经发送完毕,要求释放连接)
  • 窗口:窗口字段指出了现在允许对方发送的数据量。窗口值是经常在动态变化着。
  • 选项:最大报文段长度 MSS(用于协商TCP报文段中的数据字段的最大长度);窗口扩大选项;时间戳选项

连接管理

TCP是面向连接的协议。传输数据前需要先建立连接,确定初始序号、协商MSS等参数。连接建立后双方可以收发数据,工作方式是全双工的,发送方和接收方都有缓存。数据传输完毕后,需要释放连接。

建立连接的过程

image.png

TCP建立连接的过程需要双方进行三次通信,其目的是为了同步信息。为了保证数据传输的可靠性,就需要在建立连接时就双方的初始序列号达成一致,以便于在后续的数据传输中对收到的数据进行确认。

  • 第一次握手,连接发起方A发送A端的序列号;
  • 第二次握手,连接接收方B确认并返回B的序列号;
  • 第三次握手,A端确认收到B端回应的信息;

建立连接的过程需要经过三次通信,称为三次握手。这里讨论下为什么需要第三次握手:

  • 缺少第三次握手则就无法确认连接发起端是否收到接收端的信息,因此为了保证数据传输的可靠性,必须经过三次握手。
  • 因为IP层是不可靠的,TCP为了保证可靠传输,需要进行报文确认和超时重传。当第一次握手消息延迟送达的话,发送方会进行超时重传第一次握手消息。那么对于服务器B有可能收到上次延迟的第一次握手消息,以为是A发送新的建立连接的请求,服务器B就会发送连接确认的消息。由于存在第三次握手,客户A收到B的确认请求就会忽略,不会建立新的连接。

释放连接的过程

image.png

TCP连接的关闭需要四次通信,因为TCP连接是全双工(数据在两个方向能同时传递),所以每个方向必须进行单独的关闭。一方完成了它的数据发送任务后可以发送FIN来终止这个方向的连接,当一方收到FIN后,应该通知应用层另一端已经终止了那个方向的数据传送,但仍然可以继续发送数据。

  • 第一次握手,发起方A发送FIN,说明A端已经发送完数据,终止了这个方向数据传送;
  • 第二次握手,接收方B发送ACK,说明B端已经接收完A发送的数据;
  • 第三次握手,接收方B发送FIN,说明B端也已经发送完数据,并终止了这个方向的数据传送;
  • 第四次握手,发起方A发送ACK,确认A端已经接收完B发送的数据;

为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

  • 为了保证发送的最后一个ACK报文段能够到达B端。
  • 防止“已失效的连接请求报文段”出现在新连接中。在发送完最后一个ACK报文段后,再经过实践2MSL,就可以使连接内所产生的所有报文段,都从网络中消失。这样就可以使下一个新的连接中不会出现旧的报文段。

可靠传输

由于IP层提供的是不可靠的数据报传输服务,那么TCP是怎如何保证可靠传输的呢?TCP通过滑动窗口(发送和接收),并配合报文ACK以及超时重传来实现可靠通信。

image.png

A和B建立连接之后就开始进行数据传输。主机A给主机B发送一个报文段M1后,就设置一个计时器,如果超时没有B的确认M1,就重新发送报文段M1。采用该机制后,对于接收方B需要丢弃可能会收到的重复报文段;对于发送方也要丢弃重复的确认报文。

image.png

发送方主机A拥有一个发送窗口,而接收方主机B拥有一个接收窗口。不管是发送窗口还是接收窗口都是面向字节流的,每个字节一个序号,按照序号大小排列。接收窗口的大小由接收缓冲区大小决定,发送窗口的大小则由发送缓冲区和接收窗口共同决定。窗口与缓存的关系可以参考下图。

image.png

发送窗口由已发送但未收到确认的字节部分和允许发送但尚未发送的字节部分组成;接收窗口由接收到但未发送确认的字节组成。为了提高通信的效率,发送方可以发送多个报文段,而不需要等待对方的确认,但会受限于发送窗口的大小。接收方采取累积确认的方式。这就是说,接收方不必对收到的报文段逐个发送确认,而是在收到几个报文段后,对按序到达的最后一个报文段发送确认,这就表示:到这个报文段为止的所有报文段都已正确收到了。但TCP标准规定,确认推迟的时间不应超过0.5秒。

累积确认有优点也有缺点。优点是:容易实现,即使确认丢失也不必重传。但缺点是不能向发送方反映出接收方已经正确收到的所有分组的信息。如果发送方发送了前5个报文段,而中间的第3个报文段丢失了。这时接收方只能对前两个报文段发出确认。发送方无法知道后面三个报文段的下落,而只好把后面的三个报文段都再重传一次。这就叫做Go-back-N(回退N),表示需要再退回来重传已发送过的N个分组。

拥塞控制

在计算机网络中的链路容量(即带宽)、交换结点中的缓存和处理机等,都是网络的资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫做拥塞(congestion)。拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。

常见的拥塞控制的算法有四种,分别是慢开始(slow-start)、拥塞避免(congestion avoidance)、快重传(fast retransmit)和快恢复(fast recovery)。

慢开始与拥塞避免

image.png

发送方维持一个叫做拥塞窗口 cwnd (congestion window)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口(也会受到接收窗口的限制)。

慢开始算法就是由小到大逐渐增大拥塞窗口数值。通常在刚刚开始发送报文段时,先把拥塞窗口cwnd设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值。用这样的方法逐步增大发送方的拥塞窗口cwnd(这里用值1表示一个MSS)。

image.png

在一开始发送方先设置cwnd = 1,发送第一个报文段M1,接收方收到后确认M1。发送方收到对M1的确认后,把cwnd从1增大到2,于是发送方接着发送M2和M3两个报文段。接收方收到后发回对M2和M3的确认。发送方每收到一个对新报文段的确认(重传的不算在内)就使发送方的拥塞窗口加1,因此发送方在收到两个确认后,cwnd就从2增大到4,并可发送M4~M7共4个报文段(见图5-24)。因此使用慢开始算法后,每经过一个传输轮次(transmission round),拥塞窗口cwnd就加倍。

为了防止拥塞窗口cwnd增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量。慢开始门限ssthresh的用法如下:

  • 当cwnd < ssthresh时,使用上述的慢开始算法。
  • 当cwnd > ssthresh时,停止使用慢开始算法而改用拥塞避免算法。
  • 当cwnd = ssthresh时,既可使用慢开始算法,也可使用拥塞避免算法。

拥塞避免算法的思路是让拥塞窗口cwnd缓慢地增大,即每经过一个传输轮次就把发送方的拥塞窗口cwnd加1,而不是加倍。这样,拥塞窗口cwnd 按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。

无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有按时收到确认),就要把慢开始门限ssthresh设置为出现拥塞时的发送方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。

快重传与快恢复

image.png

快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等待自己发送数据时才进行捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段M3,而不必继续等待为M3设置的重传计时器到期。

image.png

快恢复算法的过程如下:当发送方连续收到三个重复确认时,把慢开始门限ssthresh减半。这是为了预防网络发生拥塞;然后开始执行拥塞避免算法,使拥塞窗口缓慢地线性增大。这是因为发送方现在认为网络很可能没有发生拥塞(如果网络发生了严重的拥塞,就不会一连有好几个报文段连续到达接收方,也就不会导致接收方连续发送重复确认)

UDP与TCP对比

传输层协议 特点 适用场景 实际应用场景
UDP 面向报文、无连接、不保证可靠交付 适用于实时应用(IP电话、视频会议、直播等)、时延低、容忍丢包 SNMP、Quic/Http3、RTP
TCP 面向字节流、有连接、可靠交付、流量控制与拥塞控制 适用于要求可靠传输的应用 Http、FTP、SMTP、TelNet

参考资料

计算机网络

TCP/IP详解

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享