计算机网络笔记-应用层/传输层/网络层(2w字详细整理)

文章目录

计算机网络

计算机网络概述

计算机网络是由若干结点和连接这些结点的链路组成,计算机网络是互联互通的,无主从关系的计算机集合.网络之间可以通过路由器连接起来,组成一个更大的计算机网络,称为互连网.即网络的网络.网络许多计算机连接在一起,互连网把许多计算机网络通过路由器连接在一起.与网络相连的计算机通常称为主机.

image-20220919114020179

互连网(internet)是一个通用名词,它泛指由多个计算机网络互连形成的计算机网络.而大写的Internet(互联网)则泛指当前世界最大的,最开放的,由众多网络相互连接而形成的特定互联网,采用TCP/IP协议族作为通信的规则,前身是美国的ARPANET.

互联网的组成

互联网从其工作范围分为两个部分,一部分为边缘部分,一部分为核心部分.边缘部分是所有连接在互联网的主机组的,这部分是由用户直接使用的.另一部分是核心部分,由大量网络和大量路由器构成,为边缘部分提供服务.

我们实现互联网的目的就是为了不同的主机之间可以进行通信,即主机A上的某个进程a要和主机B的某个进程b进行通信,即计算机之间通信.

网络边缘部分进行通信通常划分为两种方式:客户端(Client)/服务器(Server)与对等方式(P2P).

网络边缘部分
C/S方式

客户端-服务器方式即我们耳熟能详的Client/Server结构,这种方式是互联网最常用的,最传统的方式.服务器为提供服务方,客户端为请求服务方.

  • 客户端向服务器请求服务.
  • 服务器响应客户端的请求.
P2P对等方式

对等方式P2P方式是指两台主机在通信时并不区分哪一个是服务请求方,哪一个是服务提供方.只要这些设备都安装了P2P软件,就可以互相进行通信.

网络核心部分

网络核心部分起到核心作用的是路由器,路由器是实现分组交换的关键构件,任务是转发收到的分组.

电路交换

为了弄清分组交换,我们先简单介绍一下电路交换.在电话问世不久后,所有的电话机都需要互相连接,但是所以电话机之间两两相连接是不现实的,有N个电话机需要连接则需要构建N*(N-1) / 2条线路.所以为了解决这一问题,出现了交换机,每一个电话机只需要连接到交换机,由交换机负责电路通信.

从资源的分配角度看,交换是按照某种方式动态的分配传输线路的资源.双方通信需要建立一条专用的物理通路,在双方通信时,资源不会被释放,分为建立连接-占用资源-释放连接三个步骤.这三个步骤的交换方式称为电路交换.

我们注意到当两个电话机进行通信时需要一直占用资源,当电路用来传输计算机数据时, 传输效率会很低.电路交换为了提供工作效率的其他内容如多路复用技术等内容则不做过多介绍.

分组交换

分组交换采用的是存储-转发的方式.我们将要发送的整块数据称为报文,在发送报文之前会将报文分割成若干份,在每一份数据上加一些必要的控制信息组成头部,就形成了一个分组,相比于直接发送报文,分组是互联网中最常见的传送数据单元内,分组的优势在于可以不用等待一个报文接收完毕再去发送下一个报文,利用分组加上路由器转发的特点,就像流水线一样并行进行,极大地提高了信道利用效率.每个分组的传输利用链路的全部带宽.

报文交换

与之相对应的,报文交换也采用的是存储-转发的方式.假如我们不是每次去发送一个个的分组,而是一次性发送一整个报文,整个报文先传送到相邻结点,全部存储下来再去查找转发表,转发到下一个结点,这样的方式就是报文交换.

传输延时

传输延时是指一个分组从一端到另一端所需要的时间,网络中的时延是由不同的部分组成的.

具体可以分为以下四种类型:发送时延传播时延处理时延排队时延.

发送时延:发送时延是主机或路由器发送数据帧所花费的时间.

发送时延=数据帧长度/发送速率.

传播时延:

传播时延是数据帧在传输过程中所产生的延迟.

传播时延=信道距离/电磁波在信道上的速率.

处理时延:

主机或者路由器接受到分组需要花费一定的时间进行转发,这样就产生了处理时延.

排队延时:

分组在进行网络传输时,要经过许多的路由器,在分组进入路由器中要先在路由器队列中等待处理,就产生了排队时延.

计算机网络体系概述

OSI七层模型

OSI七层模型 (Open System Interconnect),全称为开放系统互连参考模型,是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)1984年联合制定的开放系统互联参考模型,为开放式互联信息系统提供了一种功能结构的框架。

  • 同一层中的各网络节点都有相同的层次结构,具有同样的功能。
  • 同一节点内相邻层之间通过接口进行通信。
  • 七层结构中的每一层使用下一层提供的服务,并且向其上层提供服务。
  • 不同节点的同等层按照协议实现对等层之间的通信。

img

TCP/IP四层协议模型

OSI的七层协议体系结构的概念非常清楚,理论比较完善,但是它即复杂同时也不实用,TCP/IP的体系结构则完全不同,只保留了应用层,传输层,网际层和网络接口层.虽然OSI七层模型也有很大的研究价值,但是实际上TCP/IP现在在我们的网络世界中得到了非常广泛的应用.

我们将TCP/IP四层协议模型网络接口层拆开,形成五层模型.本篇笔记将以五层模型的视角来一层一层概述,了解到每一层所负责的功能和具体实现.实际应用还是TCP/IP的体系结构设计.

image-20220922165322131

应用层

网络应用的三种体系结构

本文将采用自顶向下的方向依次来描述计算机网络中,各个层之间功能的划分和简单了解具体的实现算法.我们在学习计算机网络前接触最多的应该就是应用层相关的内容,比如DNS域名解析,HTTP以及HTTPS等等协议.在这之前,我们需要先复习一下,常见的网络应用的三种架构.

分别为客户机/服务器结构(C/S),点对点结构(P2P),混合结构(Hybrid),与之前的网络边缘部分常见的两种体系结构相比,多了一个混合结构,也就是将两种结构混合在一起,那么两种混合在一起可以利用两者的优点规避两者的缺点吗?

C/S结构中,服务器提供不间断的服务,在客户端中需要与服务器进行通信,使用服务器提供的服务,不能和其他的客户机直接通信.在P2P结构中则没有一直在线的服务器,任意端系统/结点之间可以直接通信,可自由伸缩,但是难以管理.

所以在混合结构中,我们需要尽可能地利用两者的优点,规避两者的缺点,比如在文件传输时可以采用P2P结构,在文件搜索时可以采用高效的C/S结构.

image-20220929213213126

Web应用

HTTP协议

在我们使用浏览器搜索网络中的资源时,见过最多的应该就是万维网WWW,即World Wide Web,在Web中所遵循的协议就是超文本传输协议,HTTP.在C/S结构中,客户机向服务端请求服务,服务器收到客户机的请求后,响应客户机的请求,发送对应的报文.

在HTTP早期1.0版本中,使用的是非持久性连接,浏览器每次请求都需要与服务器建立一个 TCP 连接,服务器处理完成后立即断开 TCP 连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态),所以每个TCP连接中只允许传输一个对象.

HTTP是一种无状态协议,即服务器不保留与客户交易时的任何状态。

也就是说,上一次的请求对这次的请求没有任何影响,服务端也不会对客户端上一次的请求进行任何记录处理。

一个无状态连接的过程:

  • 在HTTP1.0中,假设客户机在浏览器中输入一个URL,包含了文本和十个jpeg图片的链接.
  • HTTP客户端需要向URL的服务器发起HTTP请求,端口80
  • HTTP服务器在80端口等待TCP连接请求,接受连接并通知客户端
  • HTTP客户端将请求消息通过TCP连接的套接字发出
  • HTTP服务器收到请求消息,产生响应消息,通过套接字发给客户端
  • HTTP服务器关闭TCP连接
  • HTTP收到响应消息,发现还有十张图片需要解析,则为每个图片重复以上流程…

我们可以看到,每次都解析都需要进行TCP的重新连接,在这个过程中消耗了大量的资源.如果可以减少连接就可以减轻服务器的负担,所以为了解决这一问题出现了持久性HTTP(HTTP1.1).

HTTP1.1避免了连接建立和释放的开销;通过 Content-Length 字段来判断当前请求的数据是否已经全部接受。不允许同时存在两个并行的响应。

从客户端发送一个很小的数据包到服务器并返回的时间称为RTT(Round Trip Time).在非持久性连接中,每个对象需要2个RTT的参数时间.在持久性连接中,发送响应后,TCP保持TCP连接,后续的HTTP消息可以通过这个连接发送,所以每个被引用的对象耗时为1个RTT.

HTTP消息格式

HTTP协议有两类消息,请求消息和响应消息

HTTP请求消息

请求消息的格式如图所示,由请求行+请求头+请求空行+请求主题构成

image-20220929221033145
上传输入方法

在HTTP1.0中只有POST,GET和HEAD方法,在软件开发中GET和POST方法很常见,所以不做过多叙述,本文只是简单的描述一下HEAD方法.

POST:在请求消息的消息体中上床客户的输入,例如网页需要提交表格单元的内容

GET:输入信息在请求行的URL字段上传

HEAD:是让服务器端不要将所请求的对象放入响应消息中

在HTTP1.1中新增了两个方法,分别为PUT和DELETE方法

PUT:将消息体中的文件上传到URL字段所指定的路径

DELETE:删除URL字段所指定的文件

HTTP响应消息

HTTP的响应消息与请求消息格式相似,HTTP响应消息由状态行+头部行+空行+响应消息主体构成.

常见的状态码状态码的对应状态
200客户端请求成功
304客户端发送了一个带条件的GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个304状态码
400客户端请求有语法错误,不能被服务器所理解
401请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403服务器收到请求,但是拒绝提供服务
404请求资源不存在,举个例子:输入了错误的URL
500服务器发生不可预期的错误
503服务器当前不能处理客户端的请求,一段时间后可能恢复正常
Cookie与Session

HTTP协议本身是一种无状态的协议,当一个客户机多次向服务器发起请求,服务器并不能分辨是否为同一用户,但是我们在使用网络应用时又需要实现一种有状态的会话,Cookie与Session技术解决了这一问题.

Cookie:

cookie机制采用的是在客户端保持 HTTP 状态信息的方案。当浏览器访问WEB服务器的某个资源时,WEB服务器会在HTTP响应头中添加一个键值对传送给浏览器,再由浏览器将该cookie放到客户端磁盘的一个文件中,该文件可理解为cookie域(键值对的集合),往后每次访问某个网站时,都会在请求头中带着这个网站的所有cookie值。

每一个cookie都有一个name和一个value,且name是唯一的。相同名字时,后者会覆盖掉前者

Session:

session机制采用的是在服务器端保持 HTTP 状态信息的方案。为了加速session的读取和存储,web服务器中会开辟一块内存用来保存服务器端所有的session,每个session都会有一个唯一标识sessionid,根据客户端传过来的jsessionid(cookie中),找到对应的服务器端的session。为了防止服务器端的session过多导致内存溢出,web服务器默认会给每个session设置一个有效期, 若有效期内客户端没有访问过该session,服务器就认为该客户端已离线并删除该session。

Web缓存/代理服务器技术

我们知道http协议是无状态的,所以如果有连续的请求访问同一个网页,他就会一直重复发送,这个时候,如果有一个“有状态”的服务器,对之前的请求有记录,那么它在第二次以后的请求中,就可以在缓存中直接发送给客户。

一个使用代理服务器情况下的流程

  • 用户浏览器向浏览器的互联网发送请求时,先和代理服务器中及建立TCP连接,并向代理服务器发送HTTP报文
  • 若代理服务器中有请求的对象,代理服务器就将这个对象放入HTTP响应报文中返回
  • 否则,代理服务器就代表请求的用户浏览器与互联网上的源点服务器进行TCP连接,发送HTTP报文
  • 源点服务器就将这个对象放入HTTP响应报文中返回
  • 代理服务器收到对象后,先复制在自己的本地存储器中,然后将对象返回给请求该对象的浏览器

image-20220929230850467

采用了缓存服务器的结构降低了链路通信的流量,但是存在请求内容在缓存服务器中已经被更改的情况,即服务器是更改后的最新数据,缓存中还是之前的数据,所以通过HTTP请求头标签If-Modified-Since来解决.

If-Modified-Since是标准的HTTP请求头标签,在发送HTTP请求时,把浏览器端缓存页面的最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。

如果时间一致,那么返回HTTP状态码304(不返回文件内容),客户端接到之后,就直接把本地缓存文件显示到浏览器中。

如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。

DNS解析
分布式层次式数据库

域名系统DNS用来便于人们使用的URl地址转换为IP地址,可以采用分布式层次式数据库,比如查询一个edu结尾的URL,需要先从跟服务器解析到对应的eduDNS服务器,在解析到对应的IP地址.

DNS迭代查询
  • 客户机向DNS根服务器进行请求
  • DNS返回给客户机对应的顶级域名DNS解析服务器地址
  • 客户机向顶级域名DNS解析服务器发起请求
  • DNS返回给客户机权威DNS解析服务器地址
  • 客户机向权威DNS解析服务器发起请求
  • 返回对应的IP地址
DNS递归查询
  • 客户机向DNS根服务器进行请求
  • DNS根服务器向顶级域名DNS解析服务器发起请求
  • 顶级域名DNS解析服务器向顶级域名DNS解析服务器发起请求
  • 权威服务器给顶级域名DNS服务器返回对应的IP地址
  • 顶级域名DNS服务器向DNS根服务器返回IP地址
  • DNS根服务器向客户机返回对应的IP地址
Socket套接字

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

image-20221001134444398

在两个不同设备上的应用要进行网络通信就需要用到Socket套接字来完成,需要注意的是这些方法都是由操作系统内核来完成,不同的操作系统的具体实现可能略有差异,但是核心函数依然为下图所示:

image-20221001134426252
socket函数
//返回sockfd

 int  socket(int protofamily, int type, int protocol);

socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。

  • protofamily:即协议域,又称为协议族(family)。常用的协议族有,AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
  • type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。
  • protocol:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP,它们分别对应TCP传输协议、UDP传输协议等。
bind函数
//把一个地址族中的特定地址赋给socket
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

对应的参数类型为:

  • sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字
  • addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同
  • addrlen:对应的是地址的长度

通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。

网络字节序与主机字节序
主机字节序就是我们平常说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。引用标准的Big-Endian和Little-Endian的定义如下:

a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。**由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。**字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,一个字节的数据没有顺序的问题了。

注意:在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。由于这个问题曾引发过血案!公司项目代码中由于存在这个问题,导致了很多莫名其妙的问题,所以请谨记对主机字节序不要做任何假定,务必将其转化为网络字节序再赋给socket。

listen函数与connect函数

如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。

int listen(int sockfd, int backlog);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen函数参数类型:

  • sockfd:要监听的socket描述字
  • backlog:相应socket可以排队的最大连接个数

connect函数参数类型:

  • sockfd:客户端的socket描述字
  • addr:服务器的socket地址
  • addrlen:socket地址的长度
accept函数
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 
//返回连接connect_fd

TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就向TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了。

  • sockfd:参数sockfd就是上面解释中的监听套接字,这个套接字用来监听一个端口,当有一个客户与服务器连接时,它使用这个一个端口号,而此时这个端口号正与这个套接字关联。当然客户不知道套接字这些细节,它只知道一个地址和一个端口号

  • addr:这是一个结果参数,它用来接受一个返回值,这返回值指定客户端的地址,当然这个地址是通过某个地址结构来描述的,用户应该知道这一个什么样的地址结构。如果对客户的地址不感兴趣,那么可以把这个值设置为NULL。

  • addrlen:它也是结果的参数,用来接受上述addr的结构的大小的,它指明addr结构所占有的字节个数。同样的,它也可以被设置为NULL。

    accept默认会阻塞进程,直到有一个客户连接建立后返回,它返回的是一个新可用的套接字,这个套接字是连接套接字。此时我们需要区分两种套接字:

 监听套接字: 监听套接字正如accept的参数sockfd,它是监听套接字,在调用listen函数之后,是服务器开始调用socket()函数生成的,称为监听socket描述字(监听套接字)

   连接套接字:一个套接字会从主动连接的套接字变身为一个监听套接字;而accept函数返回的是已连接socket描述字(一个连接套接字),它代表着一个网络已经存在的点点连接。

​ 一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。

连接套接字socketfd_new 并没有占用新的端口与客户端通信,依然使用的是与监听套接字socketfd一样的端口号。如果我们只采用一个套接字的话,那么在同一时刻只能有一个进程在被服务,显然不是我们所希望的。

recvmsg()/sendmsg()等函数

至此服务器与客户已经建立好连接了。可以调用网络I/O进行读写操作了,即实现了网络中不同进程之间的通信,网络I/O操作常用的一般为recvmsg()/sendmsg().具体的细节就不做过多描述了。

 ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
 ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
close函数

在服务器与客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的socket描述字,好比操作完打开的文件要调用fclose关闭打开的文件。

close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

int close(int fd);

传输层

传输层协议为运行在不同Host上的进程提供了一种逻辑通信机制,是端对端之间的,在下一层的网络层则是主机之间进行逻辑通信.在传输层中一般采用TCP或者DUP来实现.

TCP协议全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议.

UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议.

在传输层中,是应用进程之间的,一个主机会有多个进程;因此会需要多路复用和多路分用.

也就是在网络层中可能会接收来自其他不同的主机的请求,而每一个主机又会有不同的进程等待处理,所以需要在传输层进行多路复用技术和多路分用技术,来缓解这一问题.

接收端采用多路分用技术,依据收到的Segment交给正确的Socket,即不同的进程.

发送端采用多路复用技术,为每个数据块封装上头部信息,生成Segment交给网络层.

image-20221001213805232

UDP协议的无连接分用:

  • 利用端口号创建Socket
  • UDP的socket使用二元组标识: 源端口号,目的端口号
  • 当主机收到UDP段后会检查段中的目的端口号,将UDP段导向绑定在该端口号的Socket
  • 来自不同源IP地址和/或源端口号的IP数据包被导向同一个Socket

image-20221001215106186

TCP协议面向连接的分用:

  • TCP的Socket使用四元组标识: 源IP地址,源端口号,目的IP地址,目的端口号
  • 接收端利用所有的四个值将Segment导向合适的Socket
  • 服务器可能同时支持多个TCP Socket
  • Web服务器为每个客户端开不同的Socket

image-20221001221103301

TCP协议面向连接的多线程分用:

注意在上图中P2-P6P3-P5,它们仅仅只有源端口号不同

而在下图中服务器用一个进程创建多个线程即P4创建了多个线程

image-20221001221240957

UDP协议

UDP协议是基于网络层的IP协议,能够进行简单的错误校验.但是是一种Best effort的服务,也就是尽力而为的策略,可能出现丢包,非按序到达等情况.

虽然UDP传输可能会出现一些情况但是因为UDP是一种无连接的协议,所以实现简单,无需维护连接状态,头部开销小,也没有拥塞控制,可以更好的控制发送时间和速率.常用于一些容忍一定的数据丢失并且对速率敏感的应用如流媒体应用等.

image-20221003202649361

既然UDP是一种尽力而为的协议,那么如何在UDP如何实现可靠的数据传输?

在UDP中有一种简单的检测方式,就是利用校验和来检测UDP段在传输中是否发生错误(如位反转)

发送方:

  • 将段的内容视为16进制整数
  • 校验和计算,计算所有整数的和,进位加在和的最后,将得到的值按位取反得到校验和
  • 发送方将校验和放入校验和字段

接收方:

  • 计算收到的段的校验和
  • 将其与校验和字段进行对比,检测是否错误
  • 需要注意的是没有检测出错误不一定代表没有错误

校验和计算示例:

1110 0110 0110 0110

1101 0101 0101 0101


11011 1011 1011 1011

将进位1加入16位中得到1011 1011 1011 1011+1=1011 1011 1011 1100

再将16位sum求反得0100 0100 0100 0011

可靠传输协议RDT

为了保证数据的可靠性,我们就需要做到不错,不乱,不丢.可靠传输协议对应用层,传输层,网络层都很重要,但是信道的不可靠特性决定了可靠传输协议RDT的复杂性.

在应用层中,我们只需要关注数据的发送而不用关心数据是如何传递的,对于应用层来说下面的所有层都是透明的,不可见的,而传输的信道是一种不可靠的,

image-20221002142322726

  • rdt_send() 和deliver_data() 都是单向的
  • udt_send() 和rdt_rcv() 都是双向的,跟不可靠信道数据交互时,双向传送控制信息
RDT1.0

RDT1.0版本中,我们假设在不可靠的信道中传输的数据是不会发生错误的,同时也不会丢弃分组,在RDT各个版本的状态描述中,本文采用的用状态机来描述不同状态下的处理过程.

因为在RDT1.0中假设没有错误,所以发送方和接受方只需要发送数据/接受数据就可以,是一种理想的参数模型.

image-20221002143615614

RDT2.0

我们之前提到了RDT1.0版本中,假设信道是不会出错的,但是在实际的信道中,可能在传输中产生位错误的信道,所以在2.0版本中,增加了一些简单的纠错机制.

  • 增加了校验和,用于检测信道中可能反转的位
  • 接收方返回发送方的控制确认消息ACK\NAK,接受方用来返回给发送方分组是否有问题
  • 重传机制,如果收到接受方发送的NAK,那么发送方重新给接受方发送分组

image-20221002144201991

在RDT2.0中,发送方新增了一个状态用来接收ACK/NAK信号,而接受方根据分组是否损坏来判断给发送方ACK或NAK信号.

RDT2.0无错误场景:
image-20221002144733984
RDT2.0有错误情景:
image-20221002144818083
RDT2.1

rdt2.0有着一个致命的缺点,只考虑了发送方到接收方的数据传输,如果ACK/NAK信号出现了位反转,那么就离我们所预期的情况相距很远.

由此rdt2.1应运而生,在rdt2.0的基础之上,发送方在打包数据包时添加了0或者1编号,同样ACK,NAK字段上也添加了0,1字段,表示0.1号字段的确认或者否定。发送方就有了2种状态发送0号数据包,1号数据包,接收方也有了2种状态等待0号数据包和等待1号数据包。现在假设情景发送方向接收方发送0号数据包,如果接收方接收到0号数据包,返回ACK,但是ACK出现翻转,接收方处于等待1号数据状态,发送方重复发送0号数据,接收方会拒绝0号数据,避免重复。如果接收方接收到0号数据包出现错误,返回NAK,但是NAK出现翻转,接收方处于等待0号数据状态,发送方继续发送1号数据,接收方会拒绝1号数据,避免错序.

  • 为ACK/NAK增加校验和,检错并纠错
  • 如果ACK/NAK出现错误,发送方重传
  • 为了防止出现重复分组,发送方为每个分组增加序列号
  • 接受方丢弃重复分组
RDT2.1发送方,对应ACK/NAK破坏:
image-20221002150141745
RDT2.1接收方,对应ACK/NAK破坏:

image-20221002150210433

为什么0,1两个序号就可以实现?

答案很简单,因为是SW协议,两个进程需要保持同步状态后才进行下一次操作,只需要保留当前的序号包以及下一次的序号包就可以,所以不需要保留更多的状态.

为什么当ACK信号产生位反转,接受方收到后为什么发送一个ACK状态?

当ACK信号产生位反转后,发送方会重新发送0号分组,说明我们之前发送的ACK状态产生了错误,所以我们需要告诉发送方已经成功接受到了,重新ACK,保持两个进程的同步状态.

RDT2.2

RDT2.2是基于RDT2.1的一种没有NAK消息的协议,我们一定需要ACK/NAk两个状态来表示信息的状态吗,可不可以只采用一个ACK来代表两个状态?

image-20221002151021538

RDT3.0

信道传输中,既可能发生错误,同时在路由器转发中可能会出现分组丢失的情况,如果ACK状态在存储-转发的过程中被丢失了,这样两个进程之间都不能进行同步,会一直等待对方的状态信息,因此RDT3.0中新增了一个超时重传的机制.

image-20221002151846899

虽然有了timeout这个重要的机制,但是如何设置timeout的时间就成为了我们的问题

如下图所示,根据timeout设置的不同,可能会出现各种的问题:

  • 比如当丢包后需要一直等待timeout超时重新发送,信道利用率不高
image-20221002152508533
  • 当ACK状态信息丢失时也需要等待timeout超时后重新发送,信道利用率不高
  • 如果ACK状态没有丢失,只是在路由中阻塞了,但是timeout设置时间过短,发送方重新发送分组后就接受到了之前分组的ACK状态,就会出现早熟的问题…
image-20221002152731944

滑动窗口协议

GBN协议

GBN协议(Go-Back-N回滚N帧协议),中采用了流水线技术,为了解决RDT3.0中效率底下的问题,因为RDT3.0采用了Stop-Wait协议,所以需要一直等待一个分组被正确接受后才开始下一个.

也就是在RDT协议中,不管是发送方还是接受方,双方都只有一个缓存用来接受数据

在流水线协议中,我们希望可以缓存扩充,同时序列号也扩充,允许发送方在收到ACK之前连续发送多个分组.

  • 在GBN协议中将发送方的缓存空间称为窗口,窗口的尺寸设为N,即最多允许N个分组未确认,GBN是一种累积确认的机制,接受到ACK(n)说明序列号n(包含n)的分组已经被正确接受

  • 为空中的分组设置计时器

  • 超时Timeout(n)事件:重传序号大于等于n,还未收到ACK的所有分组.

  • 因为发生超时事件后,会重传所有序列号大于等于n的,因此存在资源浪费的情况

  • 在GBN协议中,发送方有缓存空间,而接收方只有一个分组的空间,如果没有接受到就一直发送对于的ACK信号,希望发送方重新发送

    image-20221002162959932
GBN例题

数据链路层采用后退N帧(GBN)协议,发送方已经发送了编号为0~ 7的帧。当计时器超时时,若发送方只收到0、2、3号帧的确认则发送方需要重发的帧数是多少?分别是那几个帧?

解:根据GBN协议工作原理,GBN协议的确认是累积确认,所以此时发送端需要重发的帧数是4个,依次分别是4、5、6、7号帧.

假如某一层采用了GBN协议中,假如pkt2分组发送中丢失了,那么在发送方何时重新发送,接受方会是什么状态?

如图所示,会在超时后重新发送pkt2及后面的分组,而接受方在收到其他的分组时会丢弃,一直发送ACK1(上一个的ACK状态),告诉发送方pkt2丢失了,直到成功接收pkt2后发送ACK2状态.

image-20221002165204948
SR协议

GBN协议后我们发现当一个分组丢失后,后面的所有分组都需要重新发送,就会产生大量的重复分组,因为在接受方每次只能接受一个分组,所以SR(Selective Repeat)协议相比于GBN协议,多了一个接受方的窗口.SR单独确认,可以接收乱序到达的分组.

如果收到ACK,假如该帧序号在窗口内,则SR发送方将那个被确认的帧标记为已接收。如果该帧序号是窗口的下界(最左边第一个窗口对应的序号),则窗口向前移动到具有最小序号的未确认帧处。如果窗口移动了并且有序号在窗口内的未发送帧,则发送这些帧.

每个帧都有自己的定时器,一个超时事件发生后只重传一个帧.

SR接收方将确认一个正确接收的帧而不管其是否按序。失序的帧将被缓存,并返回给发送方一个该帧的确认帧(收到谁确认谁),直到所有帧(即序号更小的帧)皆被收到为止,这时才可以将一批帧按序交付给上层,然后向前移动滑动窗口.

如果收到了窗口下界之前的帧,就返回一个ACK。其他情况,就忽略该帧.

image-20221002164648754

TCP协议

TCP协议也是在传输层中常用的协议之一,TCP协议是一种可靠的传输方式.TCP协议在通信双方发送数据之前要先创建连接,TCP连接包括Socket,连接控制变量,缓存等内容.下图为TCP报文段的格式,可以看到,相比于UDP,TCP的头部更为复杂.

image-20221003202508341
  • 序号: 在其他的文章中也可以用Seq描述,指的是数据段中第一个字节的编号,而不是数据段的编号,在建立TCP连接时,双方随机选择序列号.
    • 假如有1K的数据,拆分成两个segment,那么第二个segment的序号号通常是501或者500,是segment中第一个字节的编号;并不是segment个数的编号
  • 确认号: 即ACK信号,是希望接收的下一个字节的序列号.
    • 与GBN协议相同采用了累计确认,即收到序列号之前的所有字节都已经被正确接收.
TCP可靠数据传输

TCP的实现中,如果发送超时事件,超时时间间隔将重新设置,将超时时间间隔加倍,会导致超时时间很大,重发丢失的分组之前要等待很长时间.

为了解决这一问题,TCP采用了快速重传机制,通过重复的ACK来检测分组丢失,如果发送方收到同一数据的3个ACK,则假定该数据之后的段已经丢失,在超时之前进行重传.

因此TCP在IP层提供的不可靠服务基础上实现了可靠数据传输,采用了流水线机制,累计确认机制等.触发重传的事件不只是超时了,当收到3个重复ACK,TCP就会启动快速重传机制.

TCP流量控制

在TCP中需要进行流量控制,防止发送方传输的数据大于接受方接收的速度,会导致溢出.

接受方需要在数据段的头部字段将可用窗口大小告诉发送方,发送方接收到后需要限制自己已经发送的未收到ACK的数据不超过接受方可用窗口大小.

可用窗口大小可用粗略的计算为接受方窗口大小-[最后接收到的数据-最后读到的数据].

当可用窗口等于0时,说明接受方已经不能接受数据了,所以双方不能再继续进行信息互相发送,

所以在可用窗口等于0时,依然可用给发送方发送很小的数据,以便携带信息.

image-20221003211942894

TCP连接管理
  • 三次握手:
    • 1、发送方首先第一次请求,SYN标志位置一,发送初始自己的初始序列号.
    • 2、接收方返回一个SYNACK,返回自己的初始序列号.
    • 3、发送方(客户端)收到SYNACK,同时SYN不再置一,回复一个ACK;表示客户端收到了服务端允许建立连接的信息,可以包含信息.
image-20221003204727829
为什么三次握手?

三次握手的目的是建立可靠的通信通道,说到通信,简单来说就是数据的发生与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是否正常.

第一次握手:Client什么都不能确认,Server确认了对方发送正常,自己接收正常

第二次握手:Client确认了:自己发送、接收正常,对方发送正常、接收正常;Server确认了:对方发送正常,自己接收正常

第三次握手:Client确认了:自己发送、接收正常,对方发送正常接收正常;Server 确认了:对方发送正常,接收正常,自己发送正常,接收正常。

下面解释明明两次就可以建立连接的为什么还要加第三次的确认。

如果发送两次就可以建立连接话,那么只要客户端发送一个连接请求,服务端接收到并发送了确认,就会建立一个连接。

可能出现的问题:如果一个连接请求在网络中跑的慢,超时了,这时客户端会从发请求,但是这个跑的慢的请求最后还是跑到了,然后服务端就接收了两个连接请求,然后全部回应就会创建两个连接,浪费资源!

如果加了第三次客户端确认,客户端在接受到一个服务端连接确认请求后,后面再接收到的连接确认请求就可以抛弃不管了

TCP拥塞控制

当在一个计算机网络中,有太多的主机发送了太多的数据导致网络瘫痪.当数据被丢失后,发送方会重新发送数据,导致不断有新增的数据以及新增的重传数据.在一个有多个路由器转发的计算机网络中,一个分组被丢弃,那么上游的路由资源都会被浪费.

为了解决这一问题,我们采用了两种拥塞控制机制:端对端的拥塞控制和网络辅助的拥塞控制.

网络辅助的拥塞控制
  • 信息经过的一路的路由转发,期间的路由器都可以改变状态,接收方就可以通过这个信息知道拥塞情况.
  • 这个拥塞控制由接收方返回给发送方的.
  • 还有一种是中间网络设备直接向发送方发送控制信息分组的.当前讨论是ATM ABR

这里我们只描述一下ATM ABR拥塞控制:

在交换机中设置RM cell位(网络辅助),分别为NI 不允许增长,CI拥塞指示.在数据传输中随机插入几个网络辅助位,如果发生了拥塞,将cell中的EFCI位置1,前面的EFCI位被置1,那么在发送方返回的RM cell中置CI位.

端对端的拥塞控制

在端对端的拥塞控制中,如果发生了超时事件或者接收到三个重复的ACK,就可以感知到网络拥塞,发生丢失事件后,发送方应该降低速率.常见的有以下几种中调整速率的算法.

加性增-乘性减AIMD

  • 线性加(一个一个的加),乘性减(直接减半,快速减)

  • 逐渐增加发送速率,只到发送丢包,当发送loss后将发送窗口大小减半,即乘性减,快速的减少发送量

慢启动SS

  • 在连接建立时,将窗口大小设置为1

  • 每收到一个RTT就将窗口大小翻倍,初始速率很慢,但是会指数级增长

Threshold变量

线性增长与指数型增长的各有自己的优点,何时使用切换规避掉相应的弊端?

  • 设Threshold变量为界限,前期采用慢启动SS算法.
  • 当发送丢包后,Threshold更新为前窗口大小的1/2.
  • 以Threshold为界限,指数增长到Threshold后开始线性增长.
为什么拥塞控制在传输层?

因为数据会在传输层进行汇总,其他的应用程序无法知道网络是否阻塞,不能去调整自己的流量.

网络层

在传输层中,我们只关注了网络边缘部分端对端的服务,在网络层中我们开始进入网络核心部分,在网络层中实现的是主机到主机之间的数据传输.在网络层需要进行转发和路由的功能,在转发前我们需要路由协议来选择路径,选择后就可以根据IP地址来寻找目的地址发送给相应主机,在这个过程中如果发生了错误,我们还需要ICMP协议来进行传送差错报告.

image-20221004205334756

网络层核心功能

转发和路由

一个数据段从发送方主机发送,接受主机接收后向上层传输层交付数据段.数据段经过的链路上每个主机和路由器都运行着网络层协议,网络核心最重要的服务是分组-转发:路由器根据数据报,将数据报转发到正确输出端口.

其中有两个名词需要解释一下:

转发: 将分组从路由器的输入端口转移到合适的输出端口

路由: 确定分组从源到目的经过的路径

路由算法确定了网络中主机到主机的路径

具体的转发地址需要在路由器中建立一个路由转发表,用来确定本路由器如何转发分组

连接建立

数据分组传输之前两端主机需要首先要利用路由器等网络设备建立虚拟/逻辑连接.

  • 网络层连接:两个主机之间(路径上所有路由器等网络设备参与其中)
  • 传输层连接:两个应用进程之间(对中间网络设备透明)

网络层服务模型

与传输层的有链接服务TCP协议,无连接服务UDP协议类似.网络层也有两种服务模型,即有连接与无连接的两种网络层服务模型.数据报网络与虚电路网络就是典型的两类分组交换网络.

无连接服务:

  • 不预先为分组确定路径
  • 不同分组不同路径
  • 不同的分组可能传输路径不同
  • 数据报网络采用的就是无连接服务.

连接服务:

  • 首先为系列分组的传输确定从源到目的经过的路径,建立连接

  • 每个分组都是按照相同路径传输

  • 传输结束后拆除连接

  • 虚电路网络采用的是有连接服务

虚电路网络

虚电路是指一条从源主机到目的主机,类似于电路的路径,与电路传输不同的时,分组需要利用链路的全部带宽,而电路传输有时分复用,频分复用,以及码分复用等技术共享链路.

在虚电路网络中,呼叫建立网络之后才能进行数据传输,在传输结束后需要拆除呼叫.

每个分组需要携带一个虚电路标识(VCID),而不是目的主机地址.由虚电路经过的每个网络设备来维护虚电路连接状态.携带相同虚电路标识的分组就会沿着相同的路径进行传输.

每一个虚电路包括从源主机到目的主机的一条路径,沿路每段链路需要有一个VCID.沿路每个网络层设备利用转发表记录经过的虚电路.

image-20221004161429678

虚电路信令协议(signaling protocols),用于VC的建立,维护与拆除.但是在目前的因特网中不采用.

image-20221004202733763

VC虚电路网络是由电话网络演化而来,双方需要有可靠性需求和有保障的服务,为此简化了网络边缘部分,将网络复杂化.

数据报网络

Internet网络中,采用的是数据报网络.因为是无连接状态,所以每个分组都需要携带目的地址,路由器在通过分组的目的地址转发分组,每个分组独立选路.如果路由算法更新可能会导致相同目的地址的分组走不同的路径.

image-20221004203225502

在路由转发表中保存所有的IP地址显然是不可能的,因此转发表记录的是目的地址范围.

路由器根据目的IP地址的范围来确定从哪个接口进行转发.同时如果**转发表中两个地址范围是重合的,那么优先匹配最长前缀的接口.**关于为什么这样匹配我们后面会提到.现在只需要简单了解网络层的工作内容.

image-20221004204144662

数据包网络常用于计算机之间的数据交换,没有严格的时间要求,链路类型众多难以统一服务,需要端系统(计算机)可以自适应,性能控制和差错恢复,将网络简化,复杂化边缘部分.

IP协议

IP数据报格式
image-20221004210000599
  • 版本号: 4和6分别代表IPv4和IPv6版本
  • 首部长度字段占4位:IP分组首部长度;(4bit的话最大15),视为4字节为单位
    • 例如:5代表IP首部长度为20(5*4)字节
  • 服务类型(TOS)字段占8位:指示期望获得哪种类型的服务
    • 1998年改名为区分服务;
    • 只有在网络提供区分服务(DiffServ)时使用;
    • 一般情况下并不使用,通常IP分组的该字段(第2字节)的值为00H
  • 总长度:IP分组的字节数(首部+数据),最大的IP分组的长度为65535B,最小的IP分组为20B,所以可以封装的最大数据数为65535-20=65515B
  • 生存时间TTL: IP分组在网络中可以通过的路由器数,没通过一个路由器TTL-1,如果TTL=0,则路由器丢弃该分组.
  • 协议字段: 指示IP分组封装的是哪个协议的数据包,6代表TCP段,17代表UDP段,实现复用/分解.
  • 首部校验和:实现对IP分组的首部差错检测,计算校验和时字段置位0,利用反码算数求和,和的反码作为首部校验和字段
  • 选项字段:携带安全,源选路径,时间戳,路由记录等内容,很少被使用,后面的填充字段为选项字段服务,符合32位对齐,即保证首部长度是4的倍数.
IP分片

MTU为网路链路层数据帧可封装数据的上限,不同链路的MTU可能不同,如果下一个链路的MTU小于当前链路的MTU,那么大的IP分组就需要"分片"成多个分组.路由器只进行"分片",最后统一在目的地进行重组,在IP首部需要有字段来标志分片以及分片相对顺序.即IP首部的片偏移字段.IP协议利用一个计数器,每产生一个分组计时器加一,作为该IP分组的标识.

  • 标识字段: 标识一个IP分组,作为该IP分组的标识
  • 标志位字段: 占3位,有一个位空闲,其余两位为DF位与MF位
    • DF 置1 说明禁止分片 置0说明允许分片
    • MF 置1 说明不是最后一片 置0说明是最后一片
  • 片偏移字段: 一个IP分组分片封装原IP分组数据的相对偏移量,以8字节为单位.

假设原IP分组总长度为L,待转发链路的MTU为M,若L<M,DF=0,则可以被分片,分片时每个分片的标识复制原IP分组的标识.除了最后一个分片,其他分片均为MTU允许的最大分片.因为片偏移字段应该是8的倍数.

因此一个最大分片可封装的数据为:

image-20221004220453180

需要的总片数为:

image-20221004220531038

每片的偏移字段取值为:

image-20221004220603753

每片的总长度字段为:

image-20221004220626192

每片的MF标志位为:

image-20221004220656790

IP分组例题:

image-20221004220819695
IP编址

IP编址是针对于实现网络层功能的,交换机不在网络层而在链路层是不编址的,主要是对路由器和端系统进行IP编址.主机/路由器与物理链路的连接叫做接口.IP地址与每个接口关联.

一个IPv4地址有32比特,用来标识主机,路由器的接口.IP地址每8bit一组,一般转换为十进制表示.如果随意分配IP地址,会将路由器转发表造成不能承受的负担.

在IP地址中,前几位用作网络位,后几位被用作主机号,IP子网就是具有相同网络号的设备接口,可以不跨越路由器就可以彼此物理连接的接口.根据网络号的不同,IP地址被划分为几个不同的编址.

image-20221005203815981 image-20221005203931411

路由器接收到一个IP地址,根据IP地址判断地址类型:

  • 判断第一位是不是0,如果是0就知道这是A类地址.
  • 如果第一位不是0,判断第二位是不是0,如果是0就知道这是B类地址
  • 如果第二位不是0,判断第三位是不是0,如果是0就知道这是C类地址.
  • 如果第三位不是0,判断第四位是不是0,如果是0就知道这是D类地址.
  • 如果都不是,就知道这是一个E类地址.

注意D 类和 E 类地址是没有主机号的,所以不可用于主机 IP,D 类常被用于多播,E 类是预留的分类,暂时未使用.

在这些IP地址中,还有一些特殊的IP地址:

image-20221005204323428

A类,B类,C类地址中的私有IP地址:

  • 在A类地址中地址范围为:0.0.0.0-127.255.255.255
  • 在A类地址中有一些地址为私有地址,这些IP地址不会被外部设备访问到,由内部的IT人员管理.范围为10.0.0.0-10.255.255.255
  • 在B类地址中地址范围为:128.0.0.0-191.255.255.255
  • 在B类地址中有一些地址为私有地址,这些IP地址不会被外部设备访问到,由内部的IT人员管理.范围为172.16.0.0-172.31.255.255
  • 在C类地址中地址范围为:192.0.0.0-223.255.255.255
  • 在C类地址中有一些地址为私有地址,这些IP地址不会被外部设备访问到,由内部的IT人员管理.范围为192.168.0.0-192.168.255.255
image-20221005204428012

但是这种IP分类的IP地址缺少了地址的灵活性,同一网络下没有地址层次,同时与现实的网络不能很好地匹配,C类包含的主机数量只有28-2个,头尾两个IP地址不能表示主机.而B类地址包含的主机数又高达216-2个地址,所以出现了无地址分类地址CIDR.

无地址分类地址CIDR

这种方式不再有分类地址的概念,单纯的被划分为网络号+主机号.利用子网掩码来确定这个IP中前几位是网络号.

例如一个IP地址为: 172.32.1.112 子网掩码为 255.255.254.0

换成二进制可以表达成这样:

10101100 00100000 00000001 01110000

11111111 11111111 11111110 00000000

进行异或运算,就可以得到IP地址中的网络号.

虽然这样分配IP地址,极大地增加了地址的灵活性但是,每一个可分配地址范围去掉主机域全0和主机域全1的IP地址.当划分子网时,会造成头尾两个IP地址不能表示主机,主机号全为0的地址为网络地址.主机号全为1的地址为广播地址.虽然划分子网会有一定IP地址损失,但是性能会大大提升.

路由聚合

还记得之前提到过的转发表吗? 路由器根据分组的目的IP地址和转发表转发到不同的接口,如果每个IP地址都加入到转发表,那么显然负担是很大的.所以我们将拥有相同网络号的进行路由聚合操作.

比如223.1.0.0/23,223.1.2.0/23,223.1.3.0/24三个IP地址都要经过路由器R1的2号接口进行转发,我们可以将路由器中这几个IP地址进行路由聚合,在转发表中合并为223.1.0.0/22,通过2号接口进行转发.这样操作后路由表会进行大量的简化.

但是我们在进行网络划分时不一定会这么完美覆盖到一整个子网地址,如果这个属于其他组织的IP地址被转发到其他的组织一定会引发混乱,所以在转发表中采用了最长前缀匹配机制,即优先匹配最符合的IP地址,匹配后根据转发表转发相应的接口.

DHCP(动态主机配置协议)

我们已经了解到可以通过IP地址来确定主机的位置,那么如何为主机分配IP地址呢?

在我们的计算机中,可以通过设置计算机中的静态IP地址和子网掩码来确定主机的IP地址,但是如果有大量的主机,显然是工作量巨大.所以我们希望可以动态的给主机分配IP地址,这就是DHCP协议的由来.

在主机静态配置中有静态IP地址和子网掩码,还有一个网关的地址:这个地址就是这个子网的数据报要离开子网的时候,应该送往的接口地址.

DHCP协议中,IP地址,子网掩码,默认网关都会从服务器中动态获取,做到"即插即用"的特性.

可以支持移动用户加入网络.

下面是DHCP的工作过程:

  • 主机广播"DHCP discover"(发现报文)
  • DHCP服务器利用"DHCP offer"(提供报文)进行响应
  • 主机请求IP地址 “DHCP request” (请求报文)
  • DHCP服务器分配IP地址:“DHCP ack”(确认报文)
image-20221005220337763

0.0.0.0表示本机IP地址;255.255.255.255是广播地址
第一次主机发出的广播(发现报文),所有主机都可以接收到,但是只有DHCP服务器才会进行响应(提供报文)
为该主机分配IP地址
yladdr就是DHCP服务器给该主机分配的IP地址;
这个提供报文也是通过广播地址发出去的
第二次主机发出的仍然是广播,也是告知其他的DHCP服务器已经跟现在的这个链接上了(请求报文)
在DHCP服务器第二次回应之后,就确认绑定该IP地址的了

image-20221005222137405

DHCP协议在应用层实现,请求方需要将DHCP报文封装到UDP数据报中,通过IP广播,链路层广播.DHCP服务器方收到后会构造ACK报文,分配IP地址,子网掩码,默认网关地址,DNS服务器地址.在DHCP协议中,IP分配是有时间限制的,过期了需要重新发起请求.

网络地址转换(NAT)

网络地址转换技术NAT(Network Address Translation)主要用于实现位于内部网络的主机访问外部网络的功能。当局域网内的主机需要访问外部网络时,通过NAT技术可以将其私网地址转换为公网地址,并且多个私网用户可以共用一个公网地址,这样既可保证网络互通,又节省了公网地址.这些私有地址只需要从ISP中申请一个地址,减少了对IPv4地址的浪费.

本地设备IP变更后也不需要对外界进行通告,于此同时外部的ISP地址进行变更时,也不用修改内部网络设备IP地址,这些使用私有地址的设备对外界网络是不可见的,不可直接寻址.

私有地址访问外部网络时,需要经过路由器进行NAT地址的转换,与路由器的转发表类似,路由器中还有一个NAT地址转换表将私有地址转换为路由器中分配的一个可以被外部网络访问到的IP地址.

image-20221006110834553
  • 图中138.76.29.7为路由器可以被外部网络可以访问的接口地址
  • 在上图中,10.0.0.1:5001的进程需要向外部IP地址128.119.40.186的80端口发送请求
  • 因为转换表中记录了WAN端地址和LAN端地址,其中WAN地址中包含了路由器中分配的一个可以被外部网络访问到的IP地址,同时也为每一个私有地址分配了一个端口号,利用ISP地址+端口号来确定具体的私有地址设备,LAN端记录了请求时的原内部网络私有地址的设备IP地址.
  • 经过NAT转换表后,变成了从138.76.29.7:5001(假设将5001端口分配给此设备)请求访问外部IP地址128.119.40.186的80端口
  • 128.119.40.186接收到请求后,会响应次请求,返回报文的源地址为128.119.40.186:80,目的地址为路由器的公共IP地址138.76.29.7:5001,路由器接受后,根据端口号转发给不同的主机.
NAT地址穿透

穿透发生在外部主机向路由器划分的一个子网中的私有地址发起请求,但是客户端不能直接访问服务器,对外唯一可见地址为138.76.29.7.

  • 我们可以采取NAT地址转换的思路,静态配置NAT转换表,将某个端口固定分配给相应的私有地址.
  • 有静态配置就会有自动配置,UPnP协议就是将私有地址学习到公共IP地址,在NAT转换表中,增删端口
  • 除了上述两种思路外,我们还可以利用一个中继服务器来与双方进行连接,通过中继器来桥接两个连接的分组
互联网控制报文协议(ICMP)

IP协议如果发生错误,就会丢弃该分组,同时通过ICMP向主机发送差错报告.互联网控制报文协议(ICMP)支持主机或者路由器,ICMP可以用来返回差错报告和网络探询操作.

ICMP报文也是要封装到IP数据报中传输的.

ICMP的头部:

ICMP的头部共有8个字节,前4个字节是分别为类型、代码、检验和.

后面4个字节取决于TCP数据报或者UDP数据报等.

image-20221006225750444

ICMP差错报告报文数据:

在ICMP的数据部分中把收到的需要进行差错报告的IP数据报首部提取出来,加上IP数据报数据内容的八个字节.

思考一下后面八个字节是什么内容,为什么要加上?

因为我们在计算机网络体系中,数据报会一层层被封装向下一层传输,所以在IP数据报的数据字段中封装的是TCP或者UDP数据包的报文,所以前八个字节封装了目的端口和源端口的内容.

image-20221009211902027
差错报告报文

差错报告有五种报文:

  • 目的不可达
  • 源抑制
  • 超时/超期
  • 参数问题
  • 重定向

几种不发送ICMP差错报告报文的特殊情况:

  • 对ICMP差错报告报文不再发送ICMP差错报告报文
  • 除第1个IP数据报分片外,对所有后续分片均不发送ICMP差错报告报文
  • 对所有多播P数据报均不发送ICMP差错报告报文
  • 对具有特殊地址(如127.0.0.0或0.0.0.0)的IP数据报不发送ICMP差错报告报文
网络探询报文

网络探询有两种报文:

  • 回声请求与应答报文
  • 时间戳请求与应答报文

几种ICMP报文已不再使用:

信息请求与应答报文,子网掩码请求和应答报文路由器询问和通告报文

image-20221006224941685

路由算法与路由协议

在之前的内容中,我们知道了物理层的核心功能是路由-转发,那么我们就需要通过路由算法求解确定去往目的地网络的最佳路径.

在数据结构中,有一种数据结构叫做图.我们可以将实际中的路由器之间的关系抽象成图.

image-20221009213830341

图: G = (N, E)

N = 路由器集合= { u, v, w, x, y, z }

E = 链路集合 ={ (u,v), (u,x), (v,x), (v,w), (x,w), (x,y), (w,y), (w,z), (y,z) }

费用(Costs):链路的费用,C(u,v) = 2

路由器分组转发是通过路由表转发的,而路由表是通过各种算法得到的,从能否随网络的通信量或拓扑自适应地进行调整变化来划分.

路由算法: 寻找源到目的最小费用路径的算法.

路由算法可分为两大类:静态路由与动态路由.

静态路由

静态路由:需要手工配置,路由更新慢,优先级高,不适用于大型网络.

动态路由

路由器间彼此交换信息,按照路由算法优化出路由表项.

动态路由算法分为全局信息和分散信息:

  • 全局信息:所有路由器掌握完整的网络拓扑和链路费用信息,链路状态(LS)路由算法

  • 分散(decentralized)信息:路由器只掌握物理相连的邻居以及链路费,邻居间信息交换、运算的迭代过程,距离向量(DV)路由算法.

链路状态(LS)路由算法:

Dijkstra 算法:所有结点(路由器)掌握网络拓扑和链路费用,通过“链路状态广播”使所有结点拥有相同信息,计算从一个结点(“源” )到达所有其他结点的最短路径获得该结点的转发表,k次迭代后,得到到达k个目的结点的最短路径

符号标记:
(1)c(x,y): 结点x到结点y链路费用;如果x和y不直接相连,则=∞

(2)D(v): 从源到目的v的当前路径费用值

(3)p(v): 沿从源到v的当前路径, v的前序结点

(4)N’: 已经找到最小费用路径的结点集合

// 初始化:
 N’ = {u}
 for 所有结点v
 if v毗邻u
 then D(v) = c(u,v)
 else D(v) = ∞

 Loop
	找出不在 N’中的w ,满足D(w)最小
	将w加入N’
 	更新w的所有不在N’中的邻居v的D(v) :
 	D(v) = min( D(v), D(w) + c(w,v) )
 	//到达v的新费用或者是原先到达v的费用或者是已知的到达w的最短路径费用加上w到v的费用 
 until 所有结点在N’中
image-20221009215946820

根据Dijkstra 算法:

  • 先依次遍历所有的结点,将当前结点u加入N’即已经找到最小费用路径的结点集合
  • 找出结点u可以到达的其他结点v,w,x,y,z,以及对应的花费(如果不可达即为无穷大)
  • 在这些可以到达的结点中找出最小的D(node),满足D(w)最小.
  • 将最小的D(node)结点加入已经找到最小费用路径的结点集合.
  • 更新结点u可以到达的其他结点v,w,x,y,z. ,以及对应的花费(如果不可达即为无穷大)
  • 在这些可以到达的结点中找出最小的D(node),满足D(w)最小.
  • 将最小的D(node)结点加入已经找到最小费用路径的结点集合.
  • 当所有结点都在最小费用路径的结点集合,则说明每个结点都找到了最短路径.
image-20221009220050068

可能出现的问题:

由于动态更新,有可能有一个数据报从B刚到D,结果路径改变,有传回B,来回反复,形成震荡;最终形成TTL变成0,分组被丢弃.

距离向量(DV)路由算法:

Bellman-Ford方程(动态规划):

假设,dx(y):=从x到y最短路径的费用(距离)
则有:

image-20221009222745884

核心思想:每个结点不定时地将其自身的DV估计发送给其邻居,当x接收到邻居的新的DV估计时, 即依据B-F更新其自身的距离向量估计:Dx(y) ← minv{c(x,v) + Dv(y)} for each node y ∊ N,Dx(y)将最终收敛于实际的最小费用 dx(y),结点获得最短路径的下一跳, 该信息用于转发表中.

image-20221009224204538

特点:

  • 异步迭代: 引发每次局部迭代的因素:局部链路费用改变 和 来自邻居的DV更新
  • 分布式: 每个结点只当DV变化时才通告给邻居,邻居在必要时(其DV更新后发生改变)再通告它们的邻居
选路环路(routing loop)和计数到无穷(count-to-infinity)

每个结点的工作流程:

while(1){
	等待本地局部链路费用变化或者收到邻居的DV更新;
    重新计算DV;
    如果DV中到达任一目的距离发现改变,通告所有邻居;
}

当有链路费用发生改变时,就需要重新计算.

image-20221010210448209

如图所示,当某条链接的费用减少时,我们称之为有一个“好消息”。在网络中,好消息的传递往往很迅速。某一时刻,Y检测到它到X的链路费用由4减少为1,好消息当然要告诉大家了,于是它更新了自己的距离向量,并通知了Z。Z在收到Y的更新报文后,也更新了自己的距离向量(由5减为2),并向邻居们发送更新报文。而后,Y又收到了Z的更新报文,但它发现并没有改变自己的最低费用,于是保持不变。这样,仅仅经过了少次迭代网络就达到了静止。好消息通过网络得到了迅速传播。

但是当链路费用增加(甚至断开)时,就会出现一些无穷计数问题,如例题所示:

image-20221010211232859

还是X、Y、Z三个节点。此时Y检测到它到X的路径费用由4增加到了60。此时节点Z的距离向量为:

d(Z->X) = 5, d(Z->Y) = 1, d(Z->Z) = 0.

于是Y在更新向量时发现,咦,Z到X的距离只有5诶,那可以先到Z再到X,于是Y的距离向量更新为:

d(Y->X) = (Z到X的最短距离)5 +(Z到Y的最短距离)1 = 6, d(Y) = 0, d(z) = 1.

这个逻辑显然是错误的**,因为Z到X的距离为5的前提是要经过Y,但Y更新后的路径又要经过Z,这就形成了一个选路环路(routing-loop)问题**.

因为Y的距离向量更新了.虽然是错误的,但它还是向Z发送了更新报文。

Z收到更新报文后,发现d(Z->X) = (Y到X的最短距离)6+(Z到Y的最短距离)1 = 7,这个距离小于直接到X的距离,于是Z也更新的自己的距离向量,然后又将更新后的距离向量发给Y。

Y收到后又更新向量为8,然后再发给Z。。。这样循环往复,更新报文在Y和Z之间传来传去,直到第44次迭代后,Z算出它经由Y的路径费用大于50为止。此时,Z最终确定到X的最短路径费用是直接到达X的费用50,而Y也得到了最短路径是经Z到X的费用51。

可以看出,虽然最后还是得到了正确的信息,即最后的50和51.但是需要这样一直更新,知道这个距离大于所以其他的最短路径为止,如果X和Y之间的费用为10000,Z和X的费用是9999时,就会出现计数到无穷(count-to-infinity)的问题.

毒性逆转方法(The Reverse-Poison(Split-horizon) Hack)

为了解决无穷计数问题,我们有很多种算法可以实现,这里首先介绍毒性逆转.

它的基本思想是:如果Z的最短路径要通过邻居Y,那么它将告诉Y自己到目的节点的距离是无穷大.使得只要Z经过Y选路到X,它就会一直持续这个状态,这样Y也就不会从Z选路到X了,也就避免了环路问题.

我们将毒性逆转技术应用于上例。Y在更新自己的距离向量时,发现Z到X的距离是无穷大,于是它将d(x)无奈地更新为60,并向Z发送了更新报文。Z收到报文后更新自己的d(X)为50(直接选路到X),并发给Y更新报文(此时因为Z不需要经过Y进行选路,因此将告诉Y自己到X的距离为50)。Y在接收到Z的报文后,重新将距离更新为1 + 50 = 51,并告诉Z自己到X的距离是无穷大(实际是51)。Z收到报文后,发现最低耗费并没有改变,因此算法进入静止状态。

最大度量算法(maximum metric)

它的基本思想是定义一个最大的有效费用值,如15跳步/16跳步来表示无穷.

当出现无穷计数问题时,就会部分路由中一直反复更新链路,所以跳步当超过链路的最大有效费用值时就将距离当做无穷,视为距离不可达.

层次路由策略:

在之前的算法中,我们将路由器抽象称为一个点,当实际的网络中这显然是不可行的,因为假如有一个6亿目结点的网络,每个转发表要存储这么多的信息对于网络来说,交换量巨大会将整个链路淹没掉,同时我们也希望在每个网络管理中,可以自主控制网内的路由,实现管理自治.

基于这些需求,所以提出了层次路由的分层策略.

在之前我们需要先知道自治系统AS:自治系统是在单一技术管理体系下的多个路由器的集合,在自治系统内部使用内部网关协议(例如RIP、OSPF)和通用参数来决定如何路由数据包,在自治系统间则使用AS间路由协议来路由数据包(例如BGP).

网络是由不同的自治系统AS组成的,同时这些自治系统互相连接,所以在AS中既要设置AS内部的路由算法,还需要AS间的路由算法.

自治系统间(Inter-AS)路由任务:

假设有AS1,AS2,AS3三个自治系统如图所示连接,在AS1内某个路由收到一个在AS1之外的数据报,路由器要将报文转发给正确的网关路由器,所以对于AS1路由器就需要学习到哪些网络可以通过相邻AS2系统到达,哪些可以通过AS3到达,学习后需要将这些网络可达性信息传播给AS1内部路由器.

image-20221011204110453

假设AS1通过AS间路由协议学习到: 子网X可以通过网关1c路由器到达,但是不能通过AS2到达.

对于路由器1d,需要利用AS内部路由协议信息,确定到达网关路由的最小费用路径接口L,然后在转发表中增加入口(X,L).

在多个AS间选择:

上述例题中,子网X只能通过AS3来到达,在网络中,可以会有多个AS系统可以到达,这也是需要AS间路由协议来完成,因此在实际中我们采用的是"热土豆路由"策略.

  • 通过AS间路由协议学习到子网X可以通过多个网关到达
  • 利用AS间路由协议获得的路由信息确定到达每个网关的最小费用路径的费用
  • 热土豆路由策略:选择最小费用的网关
  • 通过转发表,确定去往最小费用网关接口L,在转发表中增加(X,L)
image-20221011204550278
Internet网络中的路由协议
AS内部路由协议
RIP协议(距离向量路由)

RIP协议是随着BSD-UNIX操作系统发布的,是一种距离向量路由算法.

在RIP协议的实现过程:

  • 设置距离度量: 将跳步数设置为15跳,每个链路1个跳步
  • 每间隔30S,邻居之间交换一次DV,成为通告.
  • 每次通告时,最多25个目的的子网(IP地址+子网掩码形式)

每间隔30S,邻居之间交换一次DV,成为通告,假如180S没有收到通告说明链路失效了,就需要重新计算路由,并向邻居发送新的通告,邻居再依次向外发送通告,过程中可能出现无穷计数问题,利用毒性逆转来预防环路,同时也设置了最大跳步数为15跳,16跳为距离无穷大.

RIP协议是应用层进程实现的协议,利用一个叫做routed的应用层进程实现,但是根据功能划分层,路由是网络层功能,因此是网络层协议.通告报文周期性通过UDP数据报发送.

image-20221011212605159

路由器运行由应用层进程实现的RIP协议,那也会运行有UDP/TCP运输层协议,但是网络参考模型中,路由器只到网络层,因为上面层次的协议也是为了完成网络层的功能,路由器本身并不是端系统到端系统的.

image-20221011211104060

路由器D的转发表:

目的子网地址(IP地址+子网掩码)下一个路由地址(IP地址+子网掩码)到目的子网的跳步数
WA2
YB2
ZB7
X1
OSPF协议(链路状态路由)

路由协议OSPF全称为Open Shortest Path First,即开放的最短路径优先协议.OSPF 最显著的特点是使用链路状态算法,区别于 RIP 路由协议使用的距离向量算法.
距离向量路由协议的工作原理:运行距离向量路由协议的路由器周期性的泛洪自己的路由表,通过路由的交互,每台路由器都从相邻的路由器学习到路由,并且加载进自己的路由表中,而对于这个网络中的所有路由器而言,他们并不清楚网络的拓扑,他们只是简单的知道要去往某个目的应该从哪里走,距离有多远. 相比之下链路状态路由协议就要复杂的多.

OSPF协议计算过程:

  • 每个路由器通过泛洪链路状态通告向外发布本地链路状态信息,例如能使OSPF的端口,可到达的邻居以及相邻的子网网段等
  • 每一个路由器通过收集其它路由器发布的链路状态通告以及自身生成的本地链路状态通告,形成一个链路状态数据库.
  • 所有路由器上的链路状态数据库是相同的。通过链路状态数据库,每台路由器计算一个以自己为根,以网络中其它节点为叶的最短路径树.
  • 通过每台路由器计算的最短路径树得出了到网络中其它节点的路由表.

OSPF的优点:

  • OSPF协议中直接封装到IP数据报,没有经过TCP协议.所有的OSPF报文可以通过报文认证,预防恶意入侵.
  • 与RIP协议不同,OSPF协议可以选择多个费用相同的路径.
  • 根据IP数据报中的数据报类型字段(Typeof Service),来设置不同的费用,如UDP数据报为低费用,TCP数据报设置为高费用.
  • 可以支持大规模的AS网络分层.

区边界路由器同时是一个区域的路由器也是主干网络的路由器

image-20221011215504103

主干路由器负责在主干区内运行OSPF路由算法.

image-20221011215516310

边界路由器负责AS内部的路由连接外部的AS自治系统

image-20221011215525570
AS(自治系统)间路由协议
BGP(边界网关协议)

BGP协议 (Border GatewayProtocol):是事实上采用的标准域间路由协议,将Internet“粘合”为一个整体的关键.

BGP为每个AS都提供了一种手段:

**EBGP:**从邻居AS获取子网可达性信息,运行于不同 AS 之间的 BGP 称为 EBGP。为了防止 AS 间产生环路,当 BGP 设备接收 EBGP 对等体发送的路由时,会将带有本地 AS 号的路由丢弃

**IBGP:**运行于同一 AS 内部的 BGP 称为 IBGP。为了防止 AS 内产生环路, BGP 设备不将从IBGP 对等体学到的路由通告给其他 IBGP 对等体,并与所有 IBGP 对等体建立全连接,向所有AS内部路由器传播子网可达性信息.

基于可达性信息与策略,确定到达其他网络的“好”路径.容许子网向Internet其余部分通告它的存在.

image-20221011231738696

BGP会话通过两个BGP路由器交换BGP报文,通告去往不同目的子网的路径,与距离向量路由算法不同的是,BGP是到其他AS路由的距离,而距离向量路由算法是计算AS内部之间的距离.

BGP报文交换基于半永久的TCP连接BGP报文:

  • OPEN: 与peer建立TCP连接,并认证发送方
  • UPDATE:通告新路径(或撤销原路径)
  • KEEPALIVE:在无UPDATE时,保活连接: 也用于对OPEN请求的确认
  • NOTIFICATION:报告先前报文的差错;也被用于关闭连接

当AS3通告一个子网给AS1时:

  • AS3承诺可以将数据报转发给该子网
  • AS3在通告中会尽可能的进行路由聚合,在通告的子网信息包括子网地址+BGP属性
  • BGP中有两个重要属性:
    • AS-PATH:包含子网通告所经过的AS序列,例如经过了AS1自治系统,AS2自治系统
    • NEXT-HOP:开始一个AS-PATH的路由器接口,指向下一跳AS地址.
image-20221011231501591

BGP路由选择

网关路由器收到路由通告后,利用管理者输入的策略决策接受/拒绝该路由,与此同时路由器可能获知到达某目的AS的多条路由,基于以下准则选择:

  • 本地偏好值属性:策略决策
  • 选择最短的AS-PATH
  • 选择最短的NEXT-HOP路由器:热土豆路由算法
  • 其他的附加准则
  • 21
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值