很久很久之前你不与任何其他电脑相连接孤苦伶仃。直到有一天你希望与另一台电脑 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-bb1cc-cc-cc-cc-cc-cc3aa-aa-aa-aa-aa-aa4dd-dd-dd-dd-dd-dd5假如你仍然要发给 B 一个数据包构造了如下的数据结构从网口出去。到达交换机时交换机内部通过自己维护的 MAC 地址表发现目标机器 B 的 MAC 地址 bb-bb-bb-bb-bb-bb 映射到了端口 1 上于是把数据从 1 号端口发给了 B完事~你给这个通过这样传输方式而组成的小范围的网络叫做以太网。当然最开始的时候MAC 地址表是空的是怎么逐步建立起来的呢假如在 MAC 地址表为空是你给 B 发送了如下数据由于这个包从端口 4 进入的交换机所以此时交换机就可以在 MAC地址表记录第一条数据MACaa-aa-aa-aa-aa-aa-aa端口4交换机看目标 MAC 地址bb-bb-bb-bb-bb-bb在地址表中并没有映射关系于是将此包发给了所有端口也即发给了所有机器。之后只有机器 B 收到了确实是发给自己的包于是做出了响应响应数据从端口 1 进入交换机于是交换机此时在地址表中更新了第二条数据MACbb-bb-bb-bb-bb-bb端口1过程如下经过该网络中的机器不断地通信交换机最终将 MAC 地址表建立完毕~随着机器数量越多交换机的端口也不够了但聪明的你发现只要将多个交换机连接起来这个问题就轻而易举搞定~你完全不需要设计额外的东西只需要按照之前的设计和规矩来按照上述的接线方式即可完成所有电脑的互联所以交换机设计的这种规则真的很巧妙。你想想看为什么比如 A 要发数据给 F。但是你要注意上面那根红色的线最终在 MAC 地址表中可不是一条记录呀而是要把 EFGH 这四台机器与该端口端口6的映射全部记录在表中。最终两个交换机将分别记录 A ~ H 所有机器的映射记录。左边的交换机MAC 地址端口bb-bb-bb-bb-bb-bb1cc-cc-cc-cc-cc-cc3aa-aa-aa-aa-aa-aa4dd-dd-dd-dd-dd-dd5ee-ee-ee-ee-ee-ee6ff-ff-ff-ff-ff-ff6gg-gg-gg-gg-gg-gg6hh-hh-hh-hh-hh-hh6右边的交换机MAC 地址端口bb-bb-bb-bb-bb-bb1cc-cc-cc-cc-cc-cc1aa-aa-aa-aa-aa-aa1dd-dd-dd-dd-dd-dd1ee-ee-ee-ee-ee-ee2ff-ff-ff-ff-ff-ff3gg-gg-gg-gg-gg-gg4hh-hh-hh-hh-hh-hh6这在只有 8 台电脑的时候还好甚至在只有几百台电脑的时候都还好所以这种交换机的设计方式已经足足支撑一阵子了。但很遗憾人是贪婪的动物很快电脑的数量就发展到几千、几万、几十万。第三层交换机已经无法记录如此庞大的映射关系了。此时你动了歪脑筋你发现了问题的根本在于连出去的那根红色的网线后面不知道有多少个设备不断地连接进来从而使得地址表越来越大。那我可不可以让那根红色的网线接入一个新的设备这个设备就跟电脑一样有自己独立的 MAC 地址而且同时还能帮我把数据包做一次转发呢这个设备就是路由器它的功能就是作为一台独立的拥有 MAC 地址的设备并且可以帮我把数据包做一次转发你把它定在了网络层。注意路由器的每一个端口都有独立的 MAC 地址好了现在交换机的 MAC 地址表中只需要多出一条 MAC 地址 ABAB 与其端口的映射关系就可以成功把数据包转交给路由器了这条搞定。那如何做到把发送给 C 和 D甚至是把发送给 DEFGH.... 的数据包统统先发送给路由器呢不难想到这样一个点子假如电脑 C 和 D 的 MAC 地址拥有共同的前缀比如分别是C 的 MAC 地址FFFF-FFFF-CCCCD 的 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 地址