你是一台电脑,你的名字叫 A算法
好久好久以前,你不与任何其余电脑相链接,孤苦伶仃。编程
直到有一天,你但愿与另外一台电脑 B 创建通讯,因而大家各开了一个网口,用一根网线链接了起来。缓存
用一根网线链接起来怎么就能"通讯"了呢?我能够给你讲 IO、讲中断、讲缓冲区,但这不是研究网络时该关心的问题。安全
若是你纠结,要么去研究一下操做系统是如何处理网络 IO 的,要么去研究一下包是如何被网卡转换成电信号发送出去的,要么就仅仅把它当作电脑里有个小人在开枪吧~网络
反正,大家就是连起来了,而且能够通讯。数据结构
有一天,一个新伙伴 C 加入了,但聪明的大家很快发现,能够每一个人开两个网口,用一共三根网线,彼此相连。并发
随着愈来愈多的人加入,你发现身上开的网口实在太多了,并且网线密密麻麻,混乱不堪。(而实际上一台电脑根本开不了这么多网口,因此这种连线只在理论上可行,因此连不上的我就用红色虚线表示了,就是这么严谨哈哈~)布局
因而大家发明了一个中间设备,大家将网线都插到这个设备上,由这个设备作转发,就能够彼此之间通讯了,本质上和原来同样,只不过网口的数量和网线的数量减小了,再也不那么混乱。学习
你给它取名叫集线器,它仅仅是无脑将电信号转发到全部出口(广播),不作任何处理,你以为它是没有智商的,所以把人家定性在了物理层。动画
因为转发到了全部出口,那 BCDE 四台机器怎么知道数据包是否是发给本身的呢?
首先,你要给全部的链接到交换机的设备,都起个名字。原来大家叫 ABCD,但如今须要一个更专业的,全局惟一的名字做为标识,你把这个更高端的名字称为 MAC 地址。
你的 MAC 地址是 aa-aa-aa-aa-aa-aa,你的伙伴 b 的 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,完事~
你给这个经过这样传输方式而组成的小范围的网络,叫作以太网。
固然最开始的时候,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 直接发出以下数据包便可,其实网络层没有体现出做用。
但假如 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 上要设置默认网关
上一步 A 经过是否与 C 在同一个子网内,判断出本身应该把包发给路由器,那路由器的 IP 是多少呢?
其实说发给路由器不许确,应该说 A 会把包发给默认网关。
对 A 来讲,A 只能直接把包发给同处于一个子网下的某个 IP 上,因此发给路由器仍是发给某个电脑,对 A 来讲也不关心,只要这个设备有个 IP 地址就行。
因此默认网关,就是 A 在本身电脑里配置的一个 IP 地址,以便在发给不一样子网的机器时,发给这个 IP 地址。
仅此而已!
路由器如何知道C在哪里?
答案:路由表
如今 A 要给 C 发数据包,已经能够成功发到路由器这里了,最后一个问题就是,路由器怎么知道,收到的这个数据包,该从本身的哪一个端口出去,才能直接(或间接)地最终到达目的地 C 呢。
路由器收到的数据包有目的 IP 也就是 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 号端口。下一跳列尚未值,咱们先无论
配合着结构图来看(这里把子网掩码和默认网关都补齐了)
刚才说的都是 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(192.168.0.2)的 MAC 地址,将会广播一条 arp 请求,B 收到请求后,带上本身的 MAC 地址给 A 一个响应。此时 A 便更新了本身的 arp 表。
这样经过你们不断广播 arp 请求,最终全部电脑里面都将 arp 缓存表更新完整。
总结一下
好了,总结一下,到目前为止就几条规则
从各个节点的视角来看
电脑视角:
首先我要知道个人 IP 以及对方的 IP
经过子网掩码判断咱们是否在同一个子网
在同一个子网就经过 arp 获取对方 mac 地址直接扔出去
不在同一个子网就经过 arp 获取默认网关的 mac 地址直接扔出去
交换机视角:
我收到的数据包必须有目标 MAC 地址
经过 MAC 地址表查映射关系
查到了就按照映射关系从个人指定端口发出去
查不到就全部端口都发出去
路由器视角:
我收到的数据包必须有目标 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 |
思考一分钟...
详细过程动画描述:
详细过程文字描述:
1. 首先 A(192.168.0.1)经过子网掩码(255.255.255.0)计算出本身与 F(192.168.2.2)并不在同一个子网内,因而决定发送给默认网关(192.168.0.254)
2. A 经过 ARP 找到 默认网关 192.168.0.254 的 MAC 地址。
3. A 将源 MAC 地址(AAAA)与网关 MAC 地址(ABAB)封装在数据链路层头部,又将源 IP 地址(192.168.0.1)和目的 IP 地址(192.168.2.2)(注意这里千万不要觉得填写的是默认网关的 IP 地址,从始至终这个数据包的两个 IP 地址都是不变的,只有 MAC 地址在不断变化)封装在网络层头部,而后发包
4. 交换机 1 收到数据包后,发现目标 MAC 地址是 ABAB,转发给路由器1
5. 数据包来到了路由器 1,发现其目标 IP 地址是 192.168.2.2,查看其路由表,发现了下一跳的地址是 192.168.100.5
6. 因此此时路由器 1 须要作两件事,第一件是再次匹配路由表,发现匹配到了端口为 2,因而将其封装到数据链路层,最后把包从 2 号口发出去。
7. 此时路由器 2 收到了数据包,看到其目的地址是 192.168.2.2,查询其路由表,匹配到端口号为 1,准备从 1 号口把数据包送出去。
8. 但此时路由器 2 须要知道 192.168.2.2 的 MAC 地址了,因而查看其 arp 缓存,找到其 MAC 地址为 FFFF,将其封装在数据链路层头部,并从 1 号端口把包发出去。
9. 交换机 3 收到了数据包,发现目的 MAC 地址为 FFFF,查询其 MAC 地址表,发现应该从其 6 号端口出去,因而从 6 号端口把数据包发出去。
10. F 最终收到了数据包!而且发现目的 MAC 地址就是本身,因而收下了这个包
更详细且精准的过程:
读到这相信你们已经很累了,理解上述过程基本上网络层如下的部分主流程就基本疏通了,若是你想要本过程更为专业的过程描述,能够在公众号 低并发编程 后台回复 网络,得到我模拟这个过程的 Cisco Packet Tracer 源文件。
每一步包的传输都会有各层的原始数据,以及专业的过程描述
同时在此基础之上你也能够设计本身的网络拓扑结构,进行各类实验,来加深网络传输过程的理解。
至此,通过物理层、数据链路层、网络层这前三层的协议,以及根据这些协议设计的各类网络设备(网线、集线器、交换机、路由器),理论上只要拥有对方的 IP 地址,就已经将地球上任意位置的两个节点连通了。
本文通过了不少次的修改,删减了很多影响主流程的内容,就是为了让读者能抓住网络传输前三层的真正核心思想。同时网络相关的知识也是多且杂,我也还有不少搞不清楚的地方,很是欢迎你们与我交流,共同进步。