你是一台电脑,你的名字叫A,很久很久以前,你不与任何其他电脑连接,孤苦伶仃。
然后,你希望与另一台电脑B做朋友,两人铜线,于是你们各自开了一个网口,用一根网线连接了起来。
用一根网线连接起来怎么就能“”通信“”了呢?这里面需要涉及到IO,终端,缓冲区等,但这不是研究网络该关心的问题。如果你想了解,可以去研究一下操作系统是如何处理网络IO的,要么去研究一下包是如何被网卡转换成电信号发送出去的,或者你就把他当做电脑里有个小人在开枪吧。
反正你们就是连接起来,并且通信了。
第一层
有一天,有个心得伙伴C加入了,于是你们可以以每个人开两个网口,用一共三根线,彼此相连。
但是随着越来越多的人加入,你发现身上开的网口是在太多了,而且网线密密麻麻,混乱不堪(实际上一台电脑根本开不了那么多的网口,所以这种连线只在理论上可行)
于是发明了一个中间设备,你们将网线都插到这个设备上,由这个设备做转发,就可以彼此通信了,本质上和原来一样,只不过网口的数量和网线数量减少了,不在那么混乱。
给它取名叫加集线器,它仅仅是无脑的将电信号转发到所有出口(广播),不做任何处理,没有任何智商,因此将它定义在了“物理层”。
由于转发到了所有出口,那么BCDE四台机器怎么知道数据包是不是发给自己的呢?
首先,你要给所有连接到集线器的设备,都起一个名字,原来你们叫ABCD,但现在需要一个更专业的,全局唯一的名字作为标识,我们把这个更高端的名字叫做“MAC地址”。
你的地址是 aa-aa-aa-aa-aa-aa,你的伙伴的MAC地址是bb-bb-bb-bb-bb-bb,以此类推,不重复就好。
这样,A在发送数据包给B是,只要在头部拼接一个这样结构的数据就可以了。
B在收到数据包后,根据头部的目标MAC地址信息,判断这个数据包的确是发给自己,于是便收下。
其他的CDE在收到数据包后,根据头部的目标MAC地址信息,判断这个数据包并不是发给自己的,于是便丢弃。
虽然集线器使整个布局干净不少,但原来我只要发给B的消息,现在却要发给连接到集线器中的所有电脑,这样既不安全,用不节省网络资源。
第二层
如果把集线器弄得更智能一些,只发给目标MAC地址指向的那台电脑,就好了。
虽然只比集线器多了一点点区别,但看起来视乎智能了,把它叫做交换机,也正因为这一点智能,你把它放在了另一个层级,数据链路层。
如上图所示,你是这样设计。
交换机内部维护一样MAC地址表,记录着每一个MAC的地址的设备连接在其哪一个端口上。
MAC 地址 端口 bb-bb-bb-bb-bb-bb 1 cc-cc-cc-cc-cc-cc 3 aa-aa-aa-aa-aa-aa 4 dd-dd-dd-dd-dd-dd 5
假如你仍然要发给 B 一个数据包,构造了如下的数据结构从网口出去。
到达交换机时,交换机内部通过自己维护的MAC地址表,发现机器B的MAC地址bb-bb-bb-bb-bb-bb映射到了端口1上,于是把数据从1号端口发给了B,over完活。
给通过这样传输方式而组成的小范围的网络,叫做以太网。
当然最开始的时候,MAC表是空的,怎么建立起来的呢?
假如在MAC地址表为空时,你给B发送了如下数据:
由于这个包从端口4进入交换机,所以此时交换机就可以在MAC地址表记录第一条数据:
MAC:aa-aa-aa-aa-aa-aa-aa
端口:4
交换机看目标 MAC 地址(bb-bb-bb-bb-bb-bb)在地址表中并没有映射关系,于是将此包发给了所有端口,也即发给了所有机器。
之后,只有机器 B 收到了确实是发给自己的包,于是做出了响应,响应数据从端口 1 进入交换机,于是交换机此时在地址表中更新了第二条数据:
MAC:bb-bb-bb-bb-bb-bb
端口:1
过程如下:
经过该网络不断的通信,最终将MAC表建立完毕。
随着电脑的数量增多,交换机网口开始不够用了,但聪明你很快发现将多个交换机连接起来,这个问题就能解决了。
你完全不需要设计额外的东西,只需要按照之前的设计和规矩来,按照上述的接线方式即可完成所有电脑的互联,所以交换机设计的这种规则,真的很巧妙,你想想看为什么(比如A要发数据给F)。
但是你要注意,上面那根红色的线,最终在MAC地址表中可不是一条记录,而是要把EFGH这四台机器与该端口(端口6)的映射全部记录在表中。
最终,两个交换机将分别记录A-H所有机器的映射记录。
左边的交换机
MAC 地址 | 端口 |
---|---|
bb-bb-bb-bb-bb-bb | 1 |
cc-cc-cc-cc-cc-cc | 3 |
aa-aa-aa-aa-aa-aa | 4 |
dd-dd-dd-dd-dd-dd | 5 |
ee-ee-ee-ee-ee-ee | 6 |
ff-ff-ff-ff-ff-ff | 6 |
gg-gg-gg-gg-gg-gg | 6 |
hh-hh-hh-hh-hh-hh | 6 |
右边的交换机
MAC 地址 | 端口 |
---|---|
bb-bb-bb-bb-bb-bb | 1 |
cc-cc-cc-cc-cc-cc | 1 |
aa-aa-aa-aa-aa-aa | 1 |
dd-dd-dd-dd-dd-dd | 1 |
ee-ee-ee-ee-ee-ee | 2 |
ff-ff-ff-ff-ff-ff | 3 |
gg-gg-gg-gg-gg-gg | 4 |
hh-hh-hh-hh-hh-hh | 6 |
这在只有8台电脑时候还好,甚至在只有几百台电脑的时候,都还好,所以这种交换机的设计方式,已经可以撑一阵子了。
但很遗憾,电脑的数量很快发挥职能到几千,几万,几十万。
第三章
交换机已经无法记录如此庞大的映射关系了。
此时你动了歪脑筋,你发现了问题的根本在于,连出去的那根红色的网线,后面不知道有多少设备不断地连接进来,从而使地址越来越大。
那我可不可以让那根红色的网线,接入一个新的设备,这个设备跟电脑一样有自己独立的MAC地址,而且还能帮我们将数据包做一次转发呢?
这个设备就是路由器,他的功能就是,作为一台独立拥有MAC地址的设备,并且可以帮我把数据包做一次转发,把它定义在了网络层。
注意:路由器的每一个端口,都有独立的MAC地址。
好了,现在交换机的MAC地址表中,只需要多出一条MAC地址与ABAB与其端口的映射关系,就可以成功的数据传输到路由器。
那如何做到,把发送给 C 和 D,甚至是把发送给 DEFGH.... 的数据包,统统先发送给路由器呢?
不难想到这样一个点子,假如电脑 C 和 D 的 MAC 地址拥有共同的前缀,比如分别是:
C 的 MAC 地址:FFFF-FFFF-CCCC
D 的 MAC 地址:FFFF-FFFF-DDDD
那我们就可以说,将目标 MAC 地址为 FFFF-FFFF-?开头的,统统先发送给路由器。
这样是否可行呢?答案是否定的。
我们先从现实中 MAC 地址的结构入手,MAC地址也叫物理地址、硬件地址,长度为 48 位,一般这样来表示:
00-16-EA-AE-3C-40
它是由网络设备制造商生产时烧录在网卡的EPROM(一种闪存芯片,通常可以通过程序擦写)。其中前 24 位(00-16-EA)代表网络硬件制造商的编号,后 24 位(AE-3C-40)是该厂家自己分配的,一般表示系列号。只要不更改自己的 MAC 地址,MAC 地址在世界是唯一的。形象地说,MAC地址就如同身份证上的身份证号码,具有唯一性。
那如果你希望向上面那样将目标 MAC 地址表示为 FFFF-FFFF-?开头的,统一从路由器出去发给某一群设备(后面会提到这其实是子网的概念),那你就需要要求某一子网下统统买一个厂商制造的设备,要么你就需要要求厂商在生产网络设备烧录 MAC 地址时,提前按照你规划好的子网结构来定 MAC 地址,并且日后这个网络的结构都不能轻易改变。
这显然是不现实的。
于是你发明了一个新的地址,给每一台机器一个 32 位的编号,如:
11000000101010000000000000000001
你觉得有些不清晰,于是把它分成四个部分,中间用点相连。
11000000.10101000.00000000.00000001
你还觉得不清晰,于是把它转换成 10 进制。
192.168.0.1
最后你给它起了一个名字,叫做IP,现在每一台电脑既有自己的MAC地址,又有自己的IP,只不过IP地址是软件层面的,可以自己随时修改,MAC地址一般是固定的。
这样子的一个随时可以修改的IP地址,就可以根据你规划的网络拓扑图进行调整了。
如上图所示,假如我要发送数据包给ABCD其中的一台设备,不论哪一台,我都可以这样描述"将IP地址为192.168.0开头的全部发送给路由器,之后再怎么转发,交给路由器处理"
。
那么将数据交给路由器之后,路由器有事怎么把数据包转却转发给指定设备呢?
我们献给上面的组网方式中每台设备,加上自己的IP地址。
现在两个设备之间传输,除了加上数据链路层的头部之外,还要再加一个网络层的头部。加入A给B发送数据,由于他们直接连着交换机,所有A直接将数据发送给B,这时网络层IP是不体现作用的。
但是假如A发给C,A需要先将数据转发给路由器,然后再有路由器将数据转发给C。由于最底层传输依然需要依赖以太网,所以数据包分成两段。
A~路由器这段内容的包如下:
路由器到 C 这段的包如下:
上面说的两种情况(A->B,A->C),下面我们一个个来展开。
A 给 C 发数据包,怎么知道是否要通过路由器转发呢?
答案:子网。
如果源IP与目的IP处于一个子网,直接将包通过交换机发送过去。
如果源IP与目的IP不处于一个子网,就会将包传递给路由器,由路由器处理。
好,那现在只需要解决,什么叫处于一个子网就好了。
-
192.168.0.1 和 192.168.0.2 处于同一个子网
-
192.168.0.1 和 192.168.1.1 处于不同子网
这两个是我们人为规定的,即我们想表示,对于 192.168.0.1 来说:
192.168.0.xxx 开头的,就算是在一个子网,否则就是在不同的子网。
那对于计算机来说,怎么表达这个意思呢?于是人们发明了子网掩码的概念。
假如某台机器的子网掩码定为 255.255.255.0。
这表示,将源 IP 与目的 IP 分别同这个子网掩码进行与运算,相等则是在一个子网,不相等就是在不同子网,就这么简单。
比如:
-
A电脑:192.168.0.1 & 255.255.255.0 = 192.168.0.0
-
B电脑:192.168.0.2 & 255.255.255.0 = 192.168.0.0
-
C电脑:192.168.1.1 & 255.255.255.0 = 192.168.1.0
-
D电脑:192.168.1.2 & 255.255.255.0 = 192.168.1.0
那么 A 与 B 在同一个子网,C 与 D 在同一个子网,但是 A 与 C 就不在同一个子网,与 D 也不在同一个子网,以此类推。
所以。A给C发消息,A和C的IP地址分别&A机器配置的子网掩码,发现不相等,则A与C不在同一个子网,于是A将数据包发送给路由,就不管了。
A如何知道,哪个设备是路由呢?
上一步A通过是否与C在同一个子网内,判断自己应该把包发给路由器,那路由器的IP是多少呢?其实说发给路由器并不准确,应该说发给默认网关。
对于A来说,A只能将包发送给同处于一个子网下的某个IP上,所以发给路由器还是发给某台电脑,对A来说也不关心,只要这个设备有IP地址就可以了。
所以默认网关,就是A在自己电脑里配置的一个IP地址,以便A在发给不同子网的机器时,发送给这个IP地址。
问题又来了,包发送到路由器之后,又是如何将包发送给C的呢?
答案:路由表
A将包成功发送给路由器后,路由器怎么知道收到的这个包,从自己的那个端口出去,才能最终到达目的地C呢?
路由器收到的包有目的IP,需要转换成从自己那个端口出去去,很容易想到应该有张表,就像MAC地址表一样,这张表就叫路由表。
表怎么出来的,有很多路由算法,我也不懂!!!!!
不同于MAC地址表的是,路由表并不是一对一这种明确关系,下面是一张路由表结构。
目的地址 | 子网掩码 | 下一跳 | 端口 |
---|---|---|---|
192.168.0.0 | 255.255.255.0 | 0 | |
192.168.0.254 | 255.255.255.255 | 0 | |
192.168.1.0 | 255.255.255.0 | 1 | |
192.168.1.254 | 255.255.255.255 | 1 |
我们学习一种新的表示方法,由于子网掩码其实就表示前多少位表示子网的网段,所以如192.168.0.0(255.255.255.0)也可以简写为192.168.0.0/24
目的地址 | 下一跳 | 端口 |
---|---|---|
192.168.0.0/24 | 0 | |
192.168.0.254/32 | 0 | |
192.168.1.0/24 | 1 | |
192.168.1.254/32 | 1 |
这就好理解了,路由表就表示192.168.0.xxx这个子网下的,都转发到0号端口,192.168.1.xxx这个子网下的,都转发到1号端口。下一跳列还没有值,先不管他。
配合着结构图看(这里把子网掩码和默认网关都补齐)图中&比武,应该是0.
需要注意的是,刚才都是在说IP层,但是发送数据包的数据链路层需要知道MAC地址,可是我只知道IP地址怎么办呢?
答案:arp。
假如A此时不知道你同伴B的MAC地址(其实现实中就是不知道),只知道他的IP地址,应该怎么把数据传递给B呢?
答案很简单,在网络层我们需要把IP地址对应的MAC地址找到,也就是通过某种方式,找到192.168.0.2对应的MAC地址BBBB。
这种方式就是arp协议,同时电脑A和B里面也会有一张arp缓存表,表中记录着IP与MAC地址对应关系。
IP 地址 | MAC 地址 |
---|---|
192.168.0.2 | BBBB |
一开始这个表是空的,电脑A为了知道电脑B的MAC地址,将会广播一条arp请求,B收到请求后,带上自己的MAC地址给A一个响应,此时A便更新了自己的arp表。
这样通过不断的arp广播请求,最终所有电脑里面都将arp缓存表更新完整。
总结:
从各个节点来看
电脑视角:
首先我们要知道我的IP和对方的IP。
通过子网掩码判断我们是否在一个子网。
在同一个子网就通过arp获取对方mac地址直接扔出去。
不在同一个子网就通过arphuoqu默认网关的mac地址扔出去。
交换机视角:
我们收到的数据包必须有目标MAC地址
通过MAC地址表查映射关系
查到了就按照映射关系从我的按指定端口f发出去。查不到就所有端口都发出去。
路由器视角:
我收到的数据包必须有目标IP地址
通过路由表查映射关系
查到了就按照映射关系从指定的端口发出去(不在任何一个子网范围内,走路由器默认网关也是查到了)
查不到则返回一个路由不可达的数据包
通过以上你可以看出:
网络层(IP协议)本身米有传输包的功能,包的实际传输是交给数据链路层(以太网中的交换机来完成的)
涉及到的三张表:
交换机中的MAC地址表,用于映射MAC地址表和它的端口。
路由器中的路由表,用于映射IP地址(段)和它的端口
电脑和路由器中都有的arp缓存表用于缓存IP与MAC地址的映射关系
三张表的由来:
MAC地址表通过以太网内各节点之间不断地通过交换机通信,逐渐完善起来的。
路由表是由各种路由算法+人工配置起来的。
arp缓存表是不断通过arp协议的请求逐渐完善起来的。
通过以上学习,目前网络上两个节点如何发送数据包的过程就可以解释通了。
下面是一张网络拓扑图。
这时路由器 1 连接了路由器 2,所以其路由表有了下一条地址这一个概念,所以它的路由表就变成了这个样子。如果匹配到了有下一跳地址的一项,则需要再次匹配,找到其端口,并找到下一跳 IP 的 MAC 地址。
也就是说找来找去,最终必须能映射到一个端口号,然后从这个端口号把数据包发出去。
目的地址 | 下一跳 | 端口 |
---|---|---|
192.168.0.0/24 | 0 | |
192.168.0.254/32 | 0 | |
192.168.1.0/24 | 1 | |
192.168.1.254/32 | 1 | |
192.168.2.0/24 | 192.168.100.5 | |
192.168.100.0/24 | 2 | |
192.168.100.4/32 | 2 |
这时如果 A 给 F 发送一个数据包,能不能通呢?如果通的话整个过程是怎样的呢?
详细过程动画描述:
详细过程文字描述:
1.首先A(192.168.0.1)通过子网掩码计算出自己与F(192.168.2.2)并不在一个子网内,于是决定发送给默认网关(192.168.0.254)
2.A通过arp协议找到默认网关的MAC地址
3.A将源MAC地址(AAAA)与网关MAC地址(ABAB)封装在数据链路层头部,又将源IP(192.168.0.1)和网关(192.168.0.254)封装在网络层头部,然后发包。
4.交换机收到数据包后,发现目标MAC地址ABAB,将其转发给路由器1.
5.数据包来到了路由器后,发现目标ip是192.168.2.2,通过查路由表,发现下一跳IP192.168.100.5。
6.所以此时路由器需要再次匹配路由表,发现匹配到了端口2,于是将其封装在数据链路层,将包从端口2发出去。
7.此时数据包来到了路由器2,看到其目标IP192.168.2.2,查询其路由表,匹配到端口号1,备将包从端口1发送出去。
8.但此时路由器2需要知道192.168.2.2的MAC地址了,所以查看其arp缓存找MAC地址,将其封装在数据链路层头部,并从1号端口发送出去。
9.交换机3此时收到了数据包,发现了其目标MAC地址为FFFF,查询其MAC地址表,于是将数据从6端口发出去。
10.F最终收到了数据包,并且发现MAC目标地址就是自己,于是收下了此包。
到此,经过物理层,数据链路层,网络层这三层的协议,以及根据这些协议涉及的设备(网线,集线器,交换机,路由器),理论上只要拥有对方的IP地址,就已经将网络中任意两个连通。