admin管理员组

文章数量:1653999

网络层

IP协议

前置认识

  我们之前详谈过TCP协议,TCP协议主要是提供一种可靠的传输策略,但是并不能直接将报文发送给对方主机,而IP协议的本质就是提供一种将数据跨网络从A主机送到B主机的能力,而用户需要的是一种将数据 可靠的 跨网络从A主机送到B主机的能力。

 

 网络是划分了很多很多的子网的,子网之间通过路由器连接。

将数据跨网络从C主机发送到D主机,首先得先找到目标主机的子网,然后才能找到目标主机。

因此ip地址 = 目标网络 + 目标主机

这样设计的方式可以大幅提高查找目标主机时排除其他主机的效率。 

ip协议格式

  虽然协议格式看起来复杂,但是通过学习TCP协议后,有很多报头的内容我们很容易就理解了,先说简单的,复杂的后续补充。

这4位版本一般是ipv4,不过现在ipv4技术已经有点不够用了,ipv6可以解决ip地址不足的问题,但是还并没大面积推广。

关于IPV4

我们知道现在的IP地址是4字节,也就是32位,那么IP地址一共就只有2^32个,差不多就是42亿多个IP地址,我们现在几乎人手一部手机,需要一个IP地址,更何况还有电脑,电视等联网的设备都要IP地址,所以现在的情况就是IP地址严重不足了,而IPV6的IP地址大小是16字节,也就是2^128,就现在来说还是很充裕的了,但是IPV6和IPV4并不是版本升级那么简单,这两种完全不兼容的版本,所以现在还是流行IPV4。

  首先,我们还是需要搞懂两个问题:

1.报头和有效载荷如何分离。

2.如何将有效载荷交给上层。

16位总长度顾名思义也就是报文的总长度。并且我们发现,UDP是有总长度的,而TCP没有。说明不管是面向字节流还是面向数据报,都是要把数据交给IP协议处理的,在IP层以数据报的形式发送的。所以面向字节流并不是IP层的概念,其实是TCP提供给应用层,让应用层所关注到的概念。

4位首部长度也就是首部 + 选项的长度,因此IP报头的长度就是[20,60]字节,因此可以通过固定长度(4位首部长度) + 自描述字段(总长度) 来实现报头和有效载荷的分离。

8位服务类型:

3位优先权字段(已经弃用), 4位TOS字段, 和1位保留字段(必须置为0). 4位TOS分别表示: 最小延时, 最大吞吐量, 最高可靠性, 最小成本. 这四者相互冲突, 只能选择一个. 对于ssh/telnet这样的应用程序, 最小延时比较重要; 对于ftp这样的程序, 最大吞吐量比较重要,也就说数据从A主机到B主机是有多条路径可以选择的,这些都是给路由器提供转发依据的。并且这个最高可靠性也不能保证数据一定不会丢包,而已选择一条尽可能不会丢包的路径,如果还是丢包了,那就只能看上层是怎么处理的了,比如超时重传。

8位生存时间(TTL):其实数据报在网络中传输时,也可能会存在信号衰减,所以运营商在建设网络基础设施的时候,对于衰减的信号用放大器放大。这个TTL就是这个数据报经过路由器的最大跳数,最大能设置成64,每经过一个路由器,TTL就减1,如果到0了依旧没有到达目的主机,那么就会被当前路由器直接丢弃,以此来防止路由循环,导致大量的游离数据报遗存在网络中。

 8位协议:决定了要将IP的有效载荷交给上层的哪一种协议,也就是交给上层。

 32位源IP地址和32目的IP地址:我们之前在写一个网络服务的时候,需要端口号和IP地址,现在我们知道了,TCP需要的是端口号,因为它要交给上层的进程,而IP协议这里要的是源IP地址和目的IP地址,这里也解释了当时我们为什么要在用户层将字符串风格的IP地址转化为4字节的IP地址,因为路由器需要根据目的IP地址来进行路径选择。

  关于IP这里可以举一个形象的例子,比如唐僧受唐皇之令去西天取经,在这里唐皇和如来佛祖就是一个进程,唐僧其实就一个报头,他携带了他从哪里来,要到哪里去,唐僧不断通过路径选择,最终到达了目的地--西天,而所求的真经其实就是数据,所以本质上就是唐皇和如来佛祖之间的进程通信。

  在路由器里是没有TCP这个概念的,它只处理网络层及以下。只有用户的主机才有传输层这些。技术上来说路由器可以有TCP这些,但是它一般只工作在网络层。

网段划分

  我们知道IP地址分为网络号和主机号。

网络号: 保证相互连接的两个网段具有不同的标识; 主机号: 同一网段内, 主机之间具有相同的网络号, 但是必须有不同的主机号;

这样做可以把相同网络号的主机放在一起,用主机号标识不同的主机,而不同的网络号的主机,主机号可以相同。

这里我们需要注意:

1.路由器本质上也是特定的一个子网的主机,也要配置IP地址。(毕竟将数据从A主机送到B主机,只能通过路由器)

2.因为路由器能跨网段转发,所以路由器一定至少要连接两个子网,也就相当于同时在两个子网,因此路由器可以配置多个IP地址,且是一定要的,可以认为路由器有多张网卡。

3.路由器一般是一个子网中的第一台设备,一般它的IP地址是 网络号.1,但是如果路由器重启之类的就不一定了。

4.路由器的核心功能虽然是IP报文的转发,但不仅仅如此,它还能构建子网(局域网)。

如果在子网中新增一台主机,那么这个主机的网络号跟子网的网络号是一致的,但是主机号不能跟该子网中其他主机的重复。

比如我们想用手机上网,首先我们得连上该子网,比如输密码什么的,然后就会被分配一个IP地址,这个IP地址可以做到不重复,这种IP称之为内网IP。我们之前说的数据包在路由器之间转发是公网IP。

手动管理子网内的IP是相当麻烦的事情,所有有一种技术叫DHCP,能够自动给子网内新增主机结点分配IP地址,一般路由器都带有这个功能,因此路由器也可以看作一个DHCP服务器,也就可以动态分配IP地址。

所以我们的电脑的IP地址其实是只有在联网的时候才会有的。

我们说过,因为IP地址是32位的,因此总数就只有42亿多,用完就没了。因此IP地址是一种有限的资源,所以全球的IP地址是各个国家所要争取的。

过去有一种划分网络号和主机号的方案,就是将IP地址分类,分为五类。

A类 0.0.0.0到127.255.255.255 B类 128.0.0.0到191.255.255.255 C类 192.0.0.0到223.255.255.255 D类 224.0.0.0到239.255.255.255 E类 240.0.0.0到247.255.255.255 但是随着网络的飞速发展,这种分类的局限性就体现出来了,大多数组织都申请B类网络地址,导致B类地址很快就分配完了,而A类地址会浪费大量地址,因为一个子网中,可以分配给2^24个主机IP地址,而通常一个子网中并不会有这么多主机。而且B类网络也很少会把2^16(6万多)占满,也会形成浪费。 要注意的是,申请这种网络的一般都不是个人,而是组织甚至是国家层面的,而且这些都是公网。 一般都是由各个国家的运营商一起商讨IP的分配,比如中国的有移动,电信,联通。不过网络本质上不赚钱的,只有让更多人使用才赚钱。 针对这种情况,就引入了子网掩码的子网划分方案,称为CIDR。不过这种划分方案是在分类划分的基础之上的。 引入一个额外的子网掩码来区分网络号和主机号。 并且子网掩码也是一个32位正整数,通常用一串'0'来 结尾。 将IP地址和子网掩码进行 “ 按位与” 操作,得到的 结果就是网络号

 网络号和主机号的划分与这个IP地址是A类,B类还是C类无关

示例

网络号就是IP地址跟子网掩码进行按位与操作得来的,将示例的子网掩码转成二进制就是 1111.1111.1111.0000。后面是以一串0结尾的。因此可以通过调整子网掩码1的个数,来改变网络号和主机号的个数。 

并且,图中140.252.20.0和140.252.20.255这两个IP地址是不用的,140.252.20.0称之为网络号(主机号为全0),140.252.20.255这种称之为广播号(主机号为全1),这两个IP地址被特殊使用,不作为主机的IP地址。注意,子网掩码可以按任意个比特位进行划分。

而平常我们却没有感觉到有子网掩码这个概念。其实子网掩码已经被配置进全球的路由器当中了。

虽然我们在IP报文,或者TCP报文中没有看到子网掩码,但是在数据包在一个一个路由器转发中,已经被路由器处理好了。

特殊的IP地址

  IP地址的主机号为全0,就是是网络号,代表这个局域网。

  IP地址主机号为全1,就是广播号,用于给同一个链路中相互连接的所有主机发送数据包。

  127.*的IP地址用于本机环回(loop back)测试,通常是127.0.0.1。

IP地址的数量限制

  之前也谈过,目前IP地址的总数为42亿多,对于现在来说是严重不足的,更何况还有浪费。

假设现有有一个运营商申请到了一个B类IP地址,虽然B类IP地址允许一个子网最多有6万多台主机,但是实际上只有10台主机呢? 那么就会导致大量的IP地址被浪费了。所以我们就可以对这个B类网络进行子网掩码划分,比如将16位主机号中再拿出12位作为网络号,剩下的才作为主机号,这样就大量的减少了浪费的情况。所以实际网络号有28位,4位作为主机号,那么2^4 - 2 = 14,也就是能分配14个IP地址。

  所以就是我们再原来的16位网络号的基础上,再自己搭建内网,这样就多了2^12个网络号,每个网络号能分配14个IP地址。

  所以子网掩码虽然没有解决IP地址的上限,但是很大程度上缓解了浪费的问题。现在解决IP地址不足还有三种做法:

1.动态分配IP地址:只给写入网络的设备分配IP地址,因此同一个MAC地址的设备,每次接入互联网中,得到的IP地址不一定是相同的。说白了就是用时候给你,不用就回收,也就是共享IP地址。

2.NAT技术。

3.IPV6技术:不是简单的IPV4的升级版,这是两个互不相干的协议,彼此并不兼容。IPV6才是从根本上解决了IP地址不足的问题,因为它的IP地址是16字节的,它解决了上限不足的问题。

私有IP地址和公有IP地址 

  如果一个组织内部组建局域网 ,IP 地址只用于局域网内的通信 , 而不直接连到 Internet , 理论上 使用任意 IP 地址都可以, 但是 RFC 1918 规定了用于组建局域网的私有 IP 地址

10.*,前8位是网络号,共16,777,216个地址 172.16.到172.31.,前12位是网络号,共1,048,576个地址 192.168.*,前16位是网络号,共65,536个地址 包含在这个范围中的, 都成为私有IP, 其余的则称为全局IP(或公网IP); 比如学校要想搞个局域网,那么局域网内任意的IP地址都是可以的。 我们之所以能用我们的云服务器,因为它们是公网,并不是私网

 所以IP地址是被硬性的划分成为 公网IP 和 私网IP。

在Linux中使用

ifconfig

 可以查看当前网络信息。

其中可以看到我们的IP地址 192.168.0.205,以及子网掩码。这个IP地址并不是刚刚云服务器那里的公网IP,而是私有IP。 192.168.0.205不过是腾讯云或华为云的内网IP。

其实,在我们大部分人的上网生涯中,几乎用的都是私有IP,直到使用云服务器,才接触到了公网IP。

不过要彻底的理解私有IP和公网IP还需要理解运营商

我们以前在家上网,需要一个调制解调器(也就是猫),还需要一个家用路由器。但是首先需要接上光纤,然后猫的作用就是将模拟信号转为数字信号然后再给路由器,或者数字信号转模拟信号然后给光纤。

那个时候我们上网需要交钱,然后会获得一个账号和密码,并将其配置进路由器里面,然后路由器有权利访问外网了,因为访问外网要争得运营商的许可(比如电信)。

而我们知道路由器还有一个功能,就是构建局域网。虽然现在是无线的,但是原理是一样的,但是家里人可以通过路由器上网,邻居家里也可以,我们不想咋办呢?所以家用路由器又允许用户给路由器本身设置账号和密码,进行登录验证。

现在我们知道IP地址是一份很大的资源,并且是有限的,假设现在我们按国家的数量平均来分配IP地址,那么我们可以拿IP地址的前8位来划分,比如美国为0000.0001。那么美国的IP格式就是1.X.X.X。然后每个国家都有一个国际路由器,并且这些路由器都是联通的。

然后拿中国举例,中国又有30多个省,那么可以再拿6个比特位对省进行分配,省之间的路由器也是联通的,然后每个省又有很多市,那么同理,也要给市进行划分,假设这里也拿4位比特位。

假设有一个报文,将源IP地址进行子网掩码后,发现是发往中国的,那么就由中国的国际路由器接收,然后再看看是哪个省的,然后放到那个省的路由器,以此类推。所以公网IP是会根据国家,省市来划分的,报文一旦到了中国,那么后续所有的工作都是由运营商做的。

而之前我们说我们上网一般都是私网IP,那么公网和私网有什么关系呢?

家用路由器是能构建子网的,构建子网后,每一台子网中的设备都有一个IP地址,我们访问外网时,是先将数据由设备发送给路由器,然后路由器再交给对应的运营商,到了运营商后再进入公网,然后才能访问到互联网公司(比如B站)。

其中src ip 就是192.168.X.X这些,而dest ip 是 122.77.241.3/24这样的公网IP。

我们发送请求的时候,先判断目的主机是否在这个子网,如果不在,就只能交给路由器,路由器发现也不在它的子网,也就继续向上转发,然后就到了公网,最后通过目标地址找到了服务器。

然而当服务器处理请求之后,要返回响应时,发送dest ip 是私有IP,我们知道私有IP是不能出现在公网IP中的,因为私网IP可能是一样的。那该这么办呢?

我们知道公网之下有一个运营商,运营商也有路由器,而且它还有俩IP,一个是子网IP,以10开头的,也就是内部使用的IP。还有一个就是WAN口IP,这个就是一个公网IP,这个也叫做运营商的入口IP。而对我们家里的家用路由器,也有子网IP和WAN口IP,这里的子网IP也就是家里面的主机包括这个路由器所用到IP,因为家用路由器连接了运营商,家用路由器之间也是构成了一个子网的,因此家用路由器的WAN口IP就相当于运营商的内网IP。

所以,我们发出去的报文有一种策略,就是每经过一个路由器,将源IP替换成每一个路由器的WAN口IP(也就是外网IP)。也就是报文的替换,目标地址依旧不变。

那么回到服务器响应那里,服务器就可以将dest ip 设置成上一个路由器的WAN口IP。

这是我们个人跟互联网公司进行网络通信,那么其实公司给我们返回报文也是类似的原理,一般大公司都有一个入口路由器,然后通过这个入口的路由器将外来的请求发送给大公司组件的内网服务器里面进行处理,这些内网的服务器给我们返回报文也是要通过这个入口路由器入公网的。别看我们手机使用网络要给运营商钱,互联网公司同样要给运营商钱。

不过说到底,之所以要公网私网这样绕来绕去的,还是因为IP地址不足了,不同的子网中,私有IP可以相同,可以省下很多IP地址。

并且现在我们也知道了,运营商也可能在用子网的,不过运营商一定要有一个公网的路由器。

我们将私有IP不断被替换,将内网到公网的技术叫做NAT技术!

不过我们已经发现了,路由器或者运营商是可以对我们的数据报文进行替换的,虽然这里只是网络层,但是我们在使用HTTP协议的时候,数据都是明文发送的,没有加密的话,运营商也能做到在应用层读取我们的数据,然后进行替换。

至于为什么不用公网,因为我们也看到了,当IP地址划分到市的时候,已经严重不足给那多人使用了,所以才要用私网IP。因此比如将公网分配到省之后,之后就都用私网了。

所以现在IP地址严重不足,那么就是 私网 + 公网的方式构建了现在的互联网。这样局部的私有IP重复也没关系。

而且我们发现10.开头的是私网,但是它能分配的数量是千万级别的,那么就足以覆盖很多人了(比如一个市)。互联网公司一定申请的得是公网IP。

我们如果访问的IP是国外的,那么运营商也很清楚我们访问的是国外的,因此可以直接拦截掉。所以我们要上q,就是上运营商。

因为路由器具备转发报文的能力(还有构建子网),所以路由器至少要连接两个网段,所以路由器具备LAN口IP(私有IP)和WAN口IP。而家用路由器和运营商的路由器性质是类似的。

路由

  首先我们要清楚,我们的报文由上层往下发时,先要在本机内进行路由。 

  我们可以用指令

route

 来查看本机的路由表

所以主机一般拿到IP地址的查询步骤是这样的,

首先拿着目标主机的IP,跟Genmask(也就是子网掩码)进行按位与 &,如果它等于当前的Destination(目的地),那么就将该IP报文发送到这个目的地去,通过Iface(接口)行的eth0发送过去。

查询路由表的结果:

1.不清楚,也不给任何解决方案(有这种情况,但是很少,一般是路由器算法有bug)。

2.指明具体的下一跳。

3.路由器不清楚,但是转入默认路由,一般是同网段的另一台路由器。

4.到达入口路由器。

一直重复,直到到达目的IP的子网的入口处。

我们可以看看一般的主机的路由表

这台主机有两个网络接口,一个网络接口连到192.168.10.0/24网络,另一个网络接口连到 192.168.56.0/24网络; 路由表的Destination是目的网络地址,Genmask是子网掩码,Gateway是下一跳地址,Iface是发送接 口,Flags中的U标志表示此条目有效(可以禁用某些 条目),G标志表示此条目的下一跳地址是某个路由器的地址,没有G标志的条目表示目的网络地址是与本机接口直接相连的网络,不必经路由器转发

假设我们要转发的数据包的目的地址是192.168.56.3,那么与第一行的Genmask按位与比对后没有对上,于是排除掉第一行,然后发现与第二行比对上了,就通过eth1发送给下一跳。

再比如要要发送的数据包目的地址是202.11.23.2,发现比对下来都不是,直到到了最后一行,也就是缺省路由那里,然后再通过eth0转发给下一跳。

其实路由器早就不仅仅只是工作在网络层了,我们家里面的路由器就可以登录并访问,甚至路由器都可以构建子网了,所以路由器早已经能工作在应用层了,

数据链路层

对比理解数据链路层和网络层 

  实际上,我们在一台主机中,报文并没有通过网络层直接发送出去,而是要交给下一层协议,也就是数据链路层。

  数据链路层本质属于网卡的驱动层,一般数据链路层不能一次发送过大的报文。,那么也就要求上层不能交付过大的报文。

我们可以用指令

ifconfig

来查看当前主机最大能发送多大的报文。

其中这个mtu后面跟的数字就是能发送的报文的最大字节数。 这里是1500。

但是如果IP层的报文还是太大了,那么就会要求IP层对数据进行分片。为什么不是数据链路层分片呢?因为谁分片谁组装,如果在数据链路层分片的话,那么每经过一张网卡就要分片组装,影响效率。

所以IP是有可能分片的,所以IP报文中就要包含IP分片和组装的信息。

IP的分片和组装

 

这个16位标识就是用来标识不同的IP的,不同的IP报文之间的标号是不一样的。但是分片的IP报文的标识是相同的。

每个IP协议报头中的3位标志位中,其中第一位是弃用的,第二位如果是0,则表示允许分片,否则不允许。第三位用来表示结束标记,如果 这是最后一个小包,那么置为0,否则为1。 

这个13位片偏移,假设这个报文被分成了若干片,那么这个13位片偏移则表示这个报文在原始数据的偏移量是多少,它的作用就是为了将分片的报文组装在一起。

也就是上一个偏移量 + 这个数据的大小,就是这个报文的片偏移量。 

那么如何组装呢?

 假设我们将一个报文分成了3片,每片大小为1500(算上报头),但是即便是同一个报文分的片,它每一片依旧要加上IP的报头。

那么这3片报文的16位标识都是相同的,标识位第一位弃用不管,第二位都是0,第三位先不管,然后第一片的片偏移量是0,那么第二片就是1500,第三片就是3000。

前置问题:我们怎么知道一个IP被分片了?

首先第二位标记位只能说是允许分片,不一定百分之百判断这个报文是分片的。

如果这个报文分片了的话,除了第一片的报文,后面的报文的偏移量都不为0,且第二位标记位为0,并且就算是第一片虽然偏移量为0,但是它的第三位标记位为1,就说明它不是一个完整独立的IP报文,一定被分片了。

所以如果满足  偏移量!=0 或者 第三位标记 == 1,那么这就是分片的IP报文。

a.首先可以通过相同的标识将这三片聚在一起。

如果出现丢失了怎么办?

1.丢了第一个

2.丢了中间的

3.丢了最后一个

对于1,收到了很多同一个IP报文的分片报文,但是没有一个偏移量是0的,那么就可以判断是第一个丢了。

对于2,在对收到的分片报文根据片偏移排序后,发现如果有空缺,那么就是中间丢了。

对于3,如果分片报文里面没有一个结束标记位为0的,那么就是丢最后一个了。

但是不管是哪一个分片丢了,IP层都会将整个报文全部丢弃,要求对方全部重新重发。所以我们是不建议分片的。比如假设一个报文丢失的概率是千分之一,但是它被分成了四片,那么本来重发的概率是千分之一(或者丢包),现在变成千分之四了。

  但是IP层是从传输层拿数据的,数据要发多少是传输层说了算,因此我们可以发现TCP滑动窗口的大小假设即便有5000字节大小,但是依旧被划分成1000字节一个段(被称为MMS),这样的形式发送,明明一起发效率会更高一些,但是还是分段发送的原因就是这个。另外在TCP三次握手的时候,双方其实会交换自发单次发送最大报文的大小的。

另外我们要注意一个细节,分片的时候,是要算报头的大小的,标准报头大小为20字节,假设最大能发送1500字节,那么1500 = 报头(20字节) + 1480(数据)。而片偏移量是按原始报文大小为基准的,不要把新增的分片报头大小算进去了。

假设有一个IP报文的总长度为3000字节,那么分片后如下

 

那么这三片的偏移量依次为0,1500,2980。注意这个偏移量是根据原始报文大小来算的,不要把新加的报头大小算进去。

总之TCP是可以控制发送大小的,从而尽量避免分片,而UDP就没办法了,因为它是一个一个数据报发送的,大小无法控制。 

b.根据片偏移进行排序,完成组装。

最后需要注意:IP协议字段中,分片偏移字段是以8字节为单位的,因此在分片时为了更好描述分片偏移,因此每个分片(除了最后一个)大小都必须是8的整数倍大小。所以实际上假设这个ip报文还是3000字节,那么它的第一片的片偏移是0,第二片是185(185 * 8 = 1480),第三片就是370。

关于Mac地址

回到数据链路层

数据链路层解决的是直接相连的两台主机(也包括路由器)之间,进行数据交付的问题。 

每一张网卡都有唯一的一个Mac地址,

同样可以用ifconfig命令来查看,

在ether那里就是以太网的Mac地址。

Mac地址的作用是区分同一个局域网中特定的主机。 

以太网Mac帧的格式

其中数据也就是有效载荷,大部分就是上层的IP报文。

同理,对于每一层的协议我们要考虑两个问题:

1.Mac帧如果做到解包和封装?

可以看出,Mac帧采用定长报头来进行对报头和有效载荷的分离。就是解包和封装的。

其中目的主机就是下一跳主机的Mac地址,源地址就是当前这台主机的Mac地址。类型和CRC都是固定字段,能分离也能组装。

2.如何做到分用? 

根据类型的不同来进行分用,比如0800表示有效载荷是一个IP报文,0806就是ARP协议的报文。

局域网通信原理 

同一个局域网的所有主机都是连在一起,它们都有各自的IP地址和Mac地址。

如果有一台主机给另一台主机发送了数据,那么不只是目标主机,当前局域网的所有主机都能拿到报文,只是除了目标主机外,它们将报文解包后发现目的地址对不上,然后直接将报文丢弃了,只有目标主机拿到后才逐层向上解包直到用户。 

如果H1刚发送了一个信息,这时H3主机也刚好发送了一个信息,那么这种现象就称之为数据碰撞,并且H1和H3是能识别出发生数据碰撞的。

那么这时H1和H3就要进行碰撞避免算法了,其实也就是双方都等一等,错开发送信息的时间,并且在等期间,其他主机也可以通信,等完之后还是要进行数据包的重发的。所以重发不仅仅在TCP有,在数据链路层也有。

所以在局域网中,主机数越多,发生碰撞的概率也就越大。局域网在任何时刻只允许一台主机发数据。

所以现在主机A要想给主机B发送消息,那么会先查自己的路由表,然后发送给该局域网的入口路由器,接着由这个路由器发给下一跳。并且路由器也是主机,它也有数据链路层和网络层,每经过一个路由器,都会先解包分用交给它的网络层,然后查询路由表,然后再封装好Mac报头,并且此时Mac源地址已经变成了该主机自己的Mac地址,而Mac目的地址也变成了下一跳主机的Mac地址(除非该报文已经到目的地了)。

这也再一次说明了Mac帧只在局域网中有效。

我们直到交换机这个设备是工作在数据链路层的

交换机的作用是划分碰撞域,减少局域网的数据碰撞。

假设交换机左侧发送数据碰撞,那么交换机也能识别左侧的报文是碰撞报文,那么就不会转发到右侧。 

对于局域网数据碰撞可以看出,在局域网发送的报文越短越好,这个岔开各主机发送报文的时间,

所以Mac帧的数据大小范围最大是1500,最小是46字节。

所以对于网络层来说,IP报头标准大小是20字节,那么为了避免分片它的有效载荷最大是1480字节,再到传输层,TCP的标准报头大小也是20字节,因此TCP也要为了避免分片的话,每次发送的有效载荷最大是1460字节,通常把这个长度称为MMS,所以明明TCP的滑动窗口有时候有那么一大块,但还是要划分成一段一段的,就是这个原因,为了避免分片而导致丢包概率增大,在数据链路层有MTU,在TCP这里有MMS。

而双方在通信的时候,所经过的路由器的MTU可能不一样,那么MMS也就不一样,因此在三次握手的时候,双方就协商好了各自的MMS大小,并取双方的最小值。 

ARP协议

ARP协议主要原理 

  ARP协议不是一个单纯的数据链路层的协议,它是一个介于网络层和数据链路层之间的协议。它在IP协议之下,在Mac帧协议之上。

  刚刚谈过局域网通信原理,我们将数据从主机A千里迢迢送到主机B所在的局域网后,一般由入口路由器再转发给主机B,而局域网通信是需要Mac地址的,我们只直到主机B的IP地址,但是却不知道主机B的Mac地址,如何解决问题就要用到接下来要谈的ARP协议了。

  ARP的数据报格式:

注意到源MAC地址、目的MAC地址在以太网首部和ARP请求中各出现一次,对于链路层为以太网的情况是多余的,但如果链路层是其它类型的网络则有可能是必要的。 硬件类型指链路层网络类型,1为以太网; 协议类型指要转换的地址类型,0x0800为IP地址,也就是要将哪种地址转化成Mac地址。 硬件地址长度对于以太网地址为6字节;也就是当前Mac地址的长度,如果是以太网,这里就是6,代表6个字节。 比如之前我们用ifconfig命令查看过

这个ether就是以太网,后面每个冒号分隔的就代表1字节,这里数下去就是6字节。 

协议地址长度对于和IP地址为4字节;这里就是代表IP地址的长度,我们通常用IPV4,所以是4字节,一般这里设置的就是4。 op字段为1表示ARP请求,op字段为2表示ARP应答

首先我们看到外面依旧裹着一层Mac帧的报头

其中这个帧类型我们之间也说过,0800就代表这是一个IP协议,那么就会直接解包后交给IP层,如果是0806,那么则说明这是一个ARP协议,就会交给Mac帧协议的上层,也就是ARP协议,但是ARP依旧属于数据链路层的协议,可见即便是同一层,层里面也会有分层。

接下来再说说ARP的工作流程

 

 如,假设主机A要发送数据给主机B,经过路由器的不断跳转,终于到了主机B局域网的的入口路由器处,可是入口路由器并不知道主机B的Mac地址,它只知道主机B的IP地址。那么首先,路由器会先通过广播号给当前局域网的所有主机发送一个ARP请求,以此来找到目标主机的Mac地址

为方便将路由器假定为主机R,目标主机为主机B。 

在这个请求中,各自对应的参数依旧是:

Mac帧的:

以太网目的地址:由于根本就不知道是谁,于是填全F,不过全F也就代表这是一个广播Mac地址。

以太网的源地址:主机R的Mac地址。

帧类型:0806(说明是ARP协议的报文)

CRC先不管

ARP协议的:

硬件类型:1,代表是以太网。(这里假设是1,当然也有表示无线的)

协议类型: 因为这里是要将IP地址转Mac地址,所以是0x0800。

硬件地址长度:也就是Mac地址的长度,这里一般固定填6,代表6字节。

协议地址长度:就是IP地址的长度,IPV4也就是4字节,那么这里也填的是4。

op:这里填1,代表的是ARP请求。

发送端的以太网地址:MacR

发送端IP地址:IPR。(主机R的IP地址)

目的以太网地址:跟Mac帧那里一样,全F

目的IP地址:IPB。(主机B的IP地址)

这样,就构成了一个Mac帧,在局域网内对该网的所有主机发送了过去,因为Mac帧的源以太网地址填的是广播号地址,因此所有主机都要受理,并通过帧类型0806发现是ARP协议,于是就都交给ARP协议。

在同一局域网内,任何主机都会收到ARP请求,那么任何主机也会收到ARP应答。 

到了ARP软件层之后,在这么多字段里,所有主机先看的是op字段,如果是1,那么说明这是一个ARP请求,那么再看目的IP地址,如果目的主机不是自己,那么会直接丢掉这个ARP报文。

接着,主机B收到了这个ARP请求后,就要给主机R发送ARP应答了

这里就只补充相比请求不同的部分了,首先是Mac帧:
此时的目的Mac地址变成了MacR,源Mac地址变成了MacB。

然后ARP部分:
首先就是op字段,这里就要设置成2代表是应答。

然后是目的/源Mac地址对应的改变,目的/源IP地址也对应改变。

构建好ARP应答后,接着向下封装好Mac帧后就发送到局域网内了,这里已经不用全F的广播地址了。

返回应答的过程中,不像请求时那样,所有主机收到Mac帧之后都要受理,根据帧类型交付给ARP软件层,这里可以直接通过目的Mac地址进行比对,发现不是就可以直接丢弃了。

然后就是主机R收到了这个ARP应答了,Mac帧解包后,进入ARP软件层后,依旧是先看op字段,发现是2,表示这是一个应答。总之,op决定了这个ARP报文的类型。

然后主机R就顺利的拿到了主机B的Mac地址。

我们可以用指令

apr -a

来查看ARP缓存

我们可以看到IP地址都对应了一个Mac地址。

主机在经过一次ARP请求之后, 目标主机的IP地址和Mac地址会被主机临时缓存起来。有效时间一般是几十分钟不等。

在Windows的命令窗口中,也可以查看

这些都是IP地址与主机Mac地址的映射关系。

在得到这样的映射关系后,才会回到最开始,也就是主机R能真正将数据发送给主机B。 

ARP协议周边问题 

 1.ARP只有在缓存失效的时候才会进行,不必每次都做。

  2.另外ARP协议很广泛,并不是只有在入口路由器到目的主机之间才会做,路由器与路由器之间也会构成一个局域网,该局域网的入口路由器要找到下一跳也要进行ARP协议的。

  3.我们知道我们的主机有自己的内网IP地址,以及当前的子网掩码,

比如Windows下用该命令

然后还有ping命令

 那么其实我们也可以通过自己主机的内网IP与子网掩码进行按位与得到该网段的网络号之后,遍历除了主机号和广播号的所有IP地址,将它们ping一遍,这样就能拿到该网段所有主机的IP地址与Mac地址的对应关系了。

3.我们知道ARP缓存是有有效时间的,这是因为为了防止有些主机换网卡了,导致Mac地址变了,IP地址可能没变的情况。但是ARP有这样一个特点:

如果一个主机收到多次同样的ARP应答,那么会以最新的ARP应答为准。那么就可能有如下情况

主机R是路由器,在该路由器下有两台主机A,M。主机M向主机A发送大量的虚假的ARP报文,它将这个ARP报文的源IP地址修改成IPR,以此来伪造自己是主机R,但是源Mac地址依旧是MacM。

那么即便主机A缓存了IPR:MacR的映射关系,但是由于收到了很多来自主机M的ARP报文,导致主机A对于IPR的映射关系变成了IPR:MacM,也就是现在主机A将主机M误认为是路由器,那么主机A以后发送数据就向主机M发送,如果主机M拿到数据之后直接丢弃掉,那么就实现了让主机A定向断网/离线的操作。 这种攻击就称之为ARP欺骗

或者主机M也可以不将数据直接丢弃,而是将Mac帧的IPA和MacA,替换成了IPM,MacM,然后将数据转发给了主机R,主机R再将数据转发出去,然后同理,收到的应答也是主机R先发送给主机M,然后主机M再以主机R的名义转发给主机A,那么此时主机M就成了主机A与主机R之间的中间人机器。也就是基于ARP成为中间人的方式。

既然主机M能欺骗主机A,那么也可以以同样的方式欺骗主机R,也就是说成为中间人不一定只有单向欺骗的方式,也可以直接通过双向欺骗的方式成为中间人。

并且是有能够向某主机发送ARP欺骗报文的工具的,不过这里不能说,可以直接问文心一言这样的AI模型。

最后,我们知道ARP协议是为了将IP地址转Mac地址,还有一个协议RARP协议,与ARP协议反过来的,它是将Mac地址转IP地址的

也就是拿着Mac地址去找IP地址,因此比拿着IP地址找Mac地址是要容易得多的。

DNS协议 

  DNS(Domain Name System) 

也就是域名解析服务。我们现在已经知道了,我们可以拿着域名去访问服务器,但是实际上是域名先被解析成IP地址后,再通过IP地址访问的。

所以我们实际访问服务器还是根据IP地址访问的,至于为什么还要域名,这是因为为了让互联网更具有通用性,方便人们去记忆。所以我们拿着域名去访问服务器,首先浏览器会拿着域名,通过浏览器内置的DNS服务器的地址,找到DNS服务器,然后将域名解析成IP地址,然后再通过IP地址去发起请求。

所以往后要是面试官问HTTP请求到拿到网页的过程,是要先通过DNS进行域名解析,如果已经对域名和IP地址的映射关系缓存了就直接用,如果没有就先解析后拿到IP地址再发起请求。完了之后就是我们熟悉的事了,先通过TCP的套接字进行三次握手,三次握手之后构建HTTP请求,这里面分请求行,请求报头,空行和正文,然后再构建一个Request发送给对方,然会对方再构建一个响应返回,将返回拿到的信息资源交给浏览器处理,然后浏览器通过渲染就形成了我们的网页。

最开始没有域名的时候,有一个叫主机名的东西,在现代主机中会有一个文件,里面记录了主机名对应的IP地址。

Linux下可以用命令

cat /etc/hosts

 最初, 通过互连网信息中心(SRI-NIC)来管理这个hosts文件的

如果一个新计算机要接入网络, 或者某个计算机IP变更, 都需要到信息中心申请变更hosts文件. 其他计算机也需要定期下载更新新版本的hosts文件才能正确上网. 但是这样太麻烦了,于是就有了DNS系统。 一个组织的系统管理机构, 维护系统内的每个主机的IP和主机名的对应关系. 如果新计算机接入网络, 将这个信息注册到数据库中; 用户输入域名的时候, 会自动查询DNS服务器, 由DNS服务器检索数据库, 得到对应的IP地址. 至今 , 我们的计算机上仍然保留了 hosts 文件 . 在域名解析的过程中仍然会优先查找 hosts 文件的内容 这里看起来很简单,但是DNS服务其实是一种很关键的服务,如果域名解析服务出问题了,影响范围非常大。 关于域名的介绍: 主域名是用来识别主机名称和主机所属的组织机构的一种分层结构的名称。 com: 一级域名. 表示这是一个企业域名. 同级的还有 "net"(网络提供商), "org"(非盈利组织) 等. baidu: 二级域名, 公司名. www: 只是一种习惯用法. 之前人们在使用域名时, 往往命名成类似于ftp.xxx.xxx/www.xxx.xxx这样的格式, 来表示主机支持的协议.

很重要的一个面试题

 问: 浏览器输入URL后,发生的事情。 这是一个开放式的面试题,它能直接考察到对网络理解的水准 可以从三个方面来谈: 1.域名解析 + http的过程 2.提一下https 3.谈论细节:比如构建请求的时候的请求行,请求报头,正文等,并且实际在http请求之前要先进行三次握手,要先建立好链接,再构建http请求,然后再通过网络转发给对方主,对方主机再构建应答也就是响应,构建响应报头的时候也要构建状态行,响应报头,还有正文等,然后再把响应报文通过网络发送回来,浏览器拿到之后再对报文进行解析,然后对正文进行解释,解释好之后就可以把网页渲染出来了。这是最简单的回答,如果还要详谈,还可以再细说https,在通信之前还要进行密钥协商,如果还要再详细,那么就开始往TCP开始讲,比如在传输层,我们的数据其实都是字节流,通过发送缓冲区发送给对方,这里又要考虑流量控制和拥塞控制,还有超时重传,面向连接,确认应答,还可以再说说效率方面的有延迟应答,快重传等这些。再说就到了IP层,有子网划分,查路由表,还有分片和组装,再往下问还有Mac帧总之还有很多能谈的,至于究竟要谈多深,要和面试官边谈边商量。 总之,这种开放式问题比直接问什么是什么是要难很多的,不仅要考理解,还会考到语言组织能力

ICMP协议

  ICMP协议是一个网络层协议。它是在IP之上,传输层之下的。

一个新搭建好的网络, 往往需要先进行一个简单的测试, 来验证网络是否畅通; 但是IP协议并不提供可靠传输. 如果丢包了, IP协议并不能通知传输层是否丢包以及丢包的原因。 ICMP的主要功能包括: 确认IP包是否成功到达目标地址. 通知在发送过程中IP包被丢弃的原因. ICMP也是基于IP协议工作的. 但是它并不是传输层的功能, 因此人们仍然把它归结为网络层协议; ICMP只能搭配IPv4使用. 如果是IPv6的情况下, 需要是用ICMPv6; 我们平常用的ping命令其实就是用的ICMP。可以ping一个域名

这个TTL就是报文经过了53次路由器跳转。

 如,假设底层没有采用ICMP这样的协议,那么如果发生丢包了,就只能等TCP协议触发超时重传了,但是如果采用了ICMP协议,那么假设发生了丢包,它就会返回一个ICMP报文,来告诉主机A目标主机是不可达的。

在网络层,ICMP会给IP层封装一个ICMP的报头,然后再给IP层,最后再向下封装,然后再发送出去。

然而,在应用层,有一种原始套接字,它允许我们绕过传输层,直接访问网络层,比如构建ICMP。ping命令就是采用了这种方式。 

ICMP报文的格式

ICMP报文大致分为两种:
1.通知出错原因。

2.用于诊断查询。

部分类型字段的内容

一个面试很坑的问题:telnet23端口, ssh22端口, 那么ping是什么端口?

ping命令是基于ICMP的,也就是工作在网络层的,而端口号是传输层的内容,网络层根本不关心端口号这样的信息。

traceroute命令

也是基于ICMP协议实现, 能够打印出可执行程序主机, 一直到目标主机之前经历多少路由器。

NAT技术

NAT技术是解决IP地址不足的主要手段(或者说最重要的手段),它是路由器的重要功能。

NAT能够将私有IP对外通信时转为全局IP. 也就是就是一种将私有IP和全局IP相互转化的技术方法:

 

很多学校, 家庭, 公司内部采用每个终端设置私有IP, 而在路由器或必要的服务器上设置全局IP;   全局IP要求唯一, 但是私有IP不需要; 在不同的局域网中出现相同的私有IP是完全不影响的;

 之前只是简略说过主机A发送的数据报由内网到公网,期间经过路由器不断的替换源IP地址,直到将数据报发送到对方服务器,但是我们并不知道服务器又该怎样将报文转发回来给主机A。

简单回顾发出去的过程

 NAPT

  对于服务器怎么找到主机A,采用的就是NAPT技术,使用IP + port 来建立关联关系。

主机A将数据发送出去,在通过每次局域网转发的时候,都会建立一张转换表(也就是NAPT),并且通过IP + port的方式来保证K值的唯一性。

流程如下

比如首先在转发出去的时候,替换之前源IP之前:会将源IP地址 + 源端口号和目的IP + 目的端口号先组成一个Key。 替换之后:会将替换之后的源IP地址 + 源端口号和目的IP + 目的端口号再组成一个Key。

但是假设,此时主机B也要对服务器发送请求,并且端口号也是1025,那么在右侧的Key值就会和主机A右侧的Key值重合了,因为Key要具有唯一性,因此它把端口号替换成了1026,用不同的端口号来区分唯一性。

因此,NAT不仅仅只会替换IP地址,它还有可能替换端口号。

那么服务器想要返回响应的时候,它只要将响应发送到上一级路由器,然后路由器通过查转化表又不断的通过替换IP来完成外网到内网的转化。

这种关联关系也是由 NAT 路由器自动维护的 . 例如在 TCP 的情况下 , 建立连接时 , 就会生成这个表项 ; 在断开连接后 , 就会删除这个表项。 其实可以将这两个Key看作两个哈希表,都是通过Key去查Val,但是Val又是另一张表的Key。

不过如果路由器上有很多IP和端口号不会卡死吗?这里我们之前一直说我们家里面用的是家用路由器,而运营商的路由器是企业路由器,二者的功率配置等有很大差别,毕竟价格就差距很大。就算运营商的企业级路由器的端口号被打满了,它也可以再构建一个子网来管理。

NAT技术的缺陷

1.因为我们看到了NAT技术是通过每个路由器查转换表,一级一级往上直到服务器,那么它只能先由内网发送请求到外网才能建立这个转换表,而无法外网直接访问内网。

2.转化表的生成与销毁都是要开销的。但是查询成本并不高,因为类似哈希的原理。

3.通信过程中一旦NAT设备异常, 即使存在热备, 所有的TCP连接也都会断开。

内网穿透

  在不同的局域网中,我们是无法直接从主机A发送数据给主机B的

一般都是先把数据交给公网,然后再由公网交给主机B,就比如QQ,微信那样。

如果我们就是想让主机A与主机B通信,那么就必须在公网上有一个公共的服务器,比如主机A想给主机B通信的场景,那么主机B得先跟服务器建立一个TCP长链接,还得有一个专门的客户端这样的,然后主机A就可以发送数据给服务器,然后服务器再转发给主机B,这样就能实现主机A与主机B通信了,这种技术就是内网穿透。

如果玩过MC并且用过内网穿透联机的应该知道,首先需要一个伙伴先开放游戏内的局域网后(主要是开放端口号),然后通过内网穿透的客户端软件建立一个链接,然后客户端将对应的IP地址和端口号(本主机游戏的端口号)返回给你,然后你拿着返回过来的IP地址和端口号发给好伙伴,然后好伙伴就可以拿着IP地址和端口号进行联机了,本质上也就是通信,本质上也还是好伙伴发送的数据经由公共服务器的转发到你的主机上。

还有一些内网穿透的工具比如frp(github&&gitee上有),它有俩功能 frpc(client:客户端),还有frps(server:服务器)。那么未来使用就是先将服务器部署在我们的云服务器上,客户端部署在我们要通信的主机上,这个主机一般都是全天不断电不断网的,就是为了和服务器建立长链接,那么未来我们在地球的任何地方,只要能找到我们的云服务器,就能通过内网穿透的方式跟那台主机进行通信。注意:我们的云服务器并不提供真正的网络服务,它只提供消息转发。

NAT和代理服务器

  刚刚说的内网穿透其实也还只是路由器级别的,跟真正的服务器还是有差别的。

关于代理服务器,有一个很典型的例子,就是我们的校园网。如果我们连着校园网,那么我们看B站刷抖音所发出的请求并不是直接交给网络运营商的,而是要先交到学校的服务器上的。还记得我们使用校园网之前要先打开浏览器先输入账号和密码,登录之后才能使用吗?这个登录其实就是认证,这个认证是在干啥呢?

其实认证就是为了获取局域网IP地址,然后路由器并没有认证的能力,它只有分配IP地址的能力,因此就需要服务器来进行登录和认证

所以我们发送的数据先经过路由器,然后这个路由器会先转发到学校的服务器上,然后这个服务器再将数据转发到外面的运营商。这样也就说明我们发送的数据学校其实是知道的。

校园网这里为什么要有服务器呢?这是因为它要对我们的账号进行管理,要管理每个账号的缴费问题等,这样才能进行收费。这样的话我们的钱就不是交给运营商了,而是交给学校了,但是也并没有抢运营商的生意,因为学校也同样要交些钱给运营商,毕竟最终数据还要交给运营商去做处理的。

另外如果发送了一些非法请求,也可以直接在学校的服务器里进行拦截(或者屏蔽)。比如前段时间,用校园网登录不上ssh(我用的X-shell),但是换成热点后就能登录了,这就是因为一些学校会对ssh这样的一些请求做屏蔽。

或者我们有同学用校园网看电影,对方的服务器的数据依旧要先经过学校的服务器,我们看完一部电影,这部电影也在学校的服务器上缓存好了,那么有些学校搭建的一些电影网站,把这些电影放上来,用校园就可以直接看(也就是在内网直接看)。 但是如果数据加密了就不行了。

所以这种服务器也就是代理服务器,同时它是为客户端代理的,所以也叫做正向代理服务器!注意这种服务器不是什么路由器,而是Linux机器,并且可以是多台机器。

有正向代理服务器,那么还有一种就是反向代理服务器了。

比如在一家大公司里,它有很多服务器,都要处理来自各地的请求,很多服务器就有不同的IP地址,如果有很多请求都集中在一台服务器上,导致这台服务器非常繁忙,而其它服务器却又很闲,这就是服务器负载不均衡,那么为了解决这个问题,可以在这么多服务器外面再加一台服务器,但是这个服务器对请求不做任何处理,它只负责转发工作,它可以通过随机或者轮询的方式将到来的请求转发给内部的服务器,以此来达到负载均衡的目的,这种服务器也就是反向代理服务器。

我们之前说的内网穿透,其中那个公共的服务器其实就是一种反向代理服务器。

总结:

正向代理一般就是做请求的转发(一般是广域网)。

反向代理一般应用在服务器的负载均衡上(一般是局域网)。

接下来简单说说翻q的原理

首先我们访问国内服务器的流程已经知道了,正常访问国外IP的请求会被运营商直接拦截。

但是我们国内其实是有一些特殊地区,比如香港这些是可以直接访问国外的,而我们国内又可以访问这些特殊地区,那么我们可以先给特殊地区先前就建立好的服务器发送数据,然后再由这个代理服务器转发给国外服务器,然后拿到响应后,再经由国内的运营商转发回来给我,这样就完成了一次翻q。不过如果我们的数据没有加密的话,运营商是有可能会识别出来异常的,如果识别出来了就一样被会拦截掉。

这种加密协议可以我们自己做,也可以用 Socks5 协议来做。 

总之这种代理服务器也就是正向代理服务器。不过这种个人来搞的话成本是比较高的,一般都是使用别人做好的,我们一般下载好它的客户端,这个客户端就会即时的劫持我们的请求,然后通过代理服务器转发,然后再转发回来。

总之我们可以先对自己要发送的数据进行特殊加密,然后以正常的http请求去访问特殊地区的服务器,然后这个服务器(当然一般是我们部署的)将拿到的数据解密之后,再发送给外端的服务器,然后将拿到的响应进行加密,再发送回来,我们拿到后再进行解密,就完成访问了,期间绕过了运营商的检查。
常规情况下,http默认携带的数据是非http的其他数据,但是这个其他数据也可以是其他数据的报文,我们把这个叫做http的 隧道 技术。

同理,我们的服务器也不一定非要用http协议,它也可以用其他的协议,因此隧道技术不是只有http才有的。

NAT和代理服务器有哪些区别呢?

虽然NAT和代理服务器在技术实现上看起来有点像,但其实是完全不同的两个东西。

从应用上讲,NAT设备是网路基础设备,它解决的是IP地址不足的问题。而代理服务器更贴近应用,比如通过代理服务器进行翻墙,还有很多游戏都有加速器。

从底层上讲,NAT是工作在网络层的,它直接对IP地址进行了替换。而代理服务器是工作在应用层的。

从使用范围上来讲,NAT一般在局域网的出口部署,代理服务器既可以在局域网做,也可以在广域网做。

从部署位置上来讲,NAT一般集成在防火墙,路由器等硬件设备上,而代理服务器是一个软件程序,需要部署在服务器上。

本文标签: 协议链路层数据网络nat