首页 博鱼(官方)综合体育app下载 -手机版APP下载 成功案例 网站建设 电商设计 新闻中心 联系博鱼综合体育
QQ联系
电话联系
手机联系
QQ联系
电话联系
手机联系

博鱼体育app网络编程入门从未如此简单(一):假如你来设计网络会怎么做?

发布时间:2023-10-01 11:11
发布者:小编
浏览次数:

  网络编程能力对于即时通讯技术开发者来说是基本功,而计算机网络又是网络编程的理论根基,因而深刻准确地理解计算机网络知识显然能夯实你的即时通讯应用的实践品质。

  本文风格类似于52im社区里的《网络编程懒人入门》、《脑残式网络编程入门》两个系列,但通俗又不失内涵,简洁又不简陋,非常适合对计算机网络知识有向往但又有惧怕的网络编程爱好者们阅读,希望能给你带来不一样的网络知识入门视角。

  本篇主要以通俗易懂的文风,引导你理解计算机网络是如何演化成今日的样子,文中穿插了集线器、交换杨、路由器等设备的使用背景以及技术原理,由浅入深,非常适合入门者阅读。

  本文已同步发布于“即时通讯技术圈”公众号,欢迎关注。公众号上的链接是:点此进入。

  本文是系列文章中的开篇,主要涉及计算机网络的物理层、数据链路层、网络层。

  直到有一天,你希望与另一台电脑 B 建立通信,于是你们各开了一个网口,用一根网线连接了起来。

  用一根网线;了呢?我可以给你讲 IO、讲中断、讲缓冲区,但这不是研究网络时该关心的问题。

  如果你纠结,要么去研究一下操作系统是如何处理网络 IO 的,要么去研究一下包是如何被网卡转换成电信号发送出去的,要么就仅仅把它当做电脑里有个小人在开枪吧~

  有一天,一个新伙伴 C 加入了,但聪明的你们很快发现,可以每个人开两个网口,用一共三根网线,彼此相连。

  随着越来越多的人加入,你发现身上开的网口实在太多了,而且网线密密麻麻,混乱不堪。(PS:实际上一台电脑根本开不了这么多网口,所以这种连线只在理论上可行,所以连不上的我就用红色虚线表示了,就是这么严谨哈哈~)

  于是你们发明了一个中间设备,你们将网线都插到这个设备上,由这个设备做转发,就可以彼此之间通信了,本质上和原来一样,只不过网口的数量和网线的数量减少了,不再那么混乱。

  你给它取名叫:集线器,它仅仅是无脑将电信号转发到所有出口(广播),不做任何处理,你觉得它是没有智商的,因此把人家定性在了物理层。

  由于转发到了所有出口,那 BCDE 四台机器怎么知道数据包是不是发给自己的呢?

  首先,你要给所有的连接到集线器的设备,都起个名字。原来你们叫 ABCD,但现在需要一个更专业的,全局唯一的名字作为标识,你把这个更高端的名字称为MAC地址。

  这样,A 在发送数据包给 B 时,只要在头部拼接一个这样结构的数据,就可以了。

  B 在收到数据包后,根据头部的目标 MAC 地址信息,判断这个数据包的确是发给自己的,于是便收下。

  其他的 CDE 收到数据包后,根据头部的目标 MAC 地址信息,判断这个数据包并不是发给自己的,于是便丢弃。

  虽然集线器使整个布局干净不少,但原来我只要发给电脑 B 的消息,现在却要发给连接到集线器中的所有电脑,这样既不安全,又不节省网络资源。

  如果把这个集线器弄得更智能一些:“只发给目标 MAC 地址指向的那台电脑”,就好了。

  虽然只比集线器多了这一点点区别,但看起来似乎有智能了,你把这东西叫做:交换机。也正因为这一点点智能,你把它放在了另一个层级:数据链路层。

  交换机内部维护一张MAC 地址表,记录着每一个 MAC 地址的设备,连接在其哪一个端口上。

  到达交换机时,交换机内部通过自己维护的 MAC 地址表,发现目标机器 B 的 MAC 地址 bb-bb-bb-bb-bb-bb 映射到了端口 1 上,于是把数据从 1 号端口发给了 B,完事~

  由于这个包从端口 4 进入的交换机,所以此时交换机就可以在 MAC地址表记录第一条数据:

  交换机看目标 MAC 地址(bb-bb-bb-bb-bb-bb)在地址表中并没有映射关系,于是博鱼体育官方网站将此包发给了所有端口,也即发给了所有机器。

  之后,只有机器 B 收到了确实是发给自己的包,于是做出了响应,响应数据从端口 1 进入交换机,于是交换机此时在地址表中更新了第二条数据:

  随着机器数量越多,交换机的端口也不够了,但聪明的你发现,只要将多个交换机连接起来,这个问题就轻而易举搞定~

  你完全不需要设计额外的东西,只需要按照之前的设计和规矩来,按照上述的接线方式即可完成所有电脑的互联,所以交换机设计的这种规则,真的很巧妙。你想想看为什么(比如 A 要发数据给 F)。

  但是你要注意,上面那根红色的线,最终在 MAC 地址表中可不是一条记录呀,而是要把 EFGH 这四台机器与该端口(端口6)的映射全部记录在表中。

  这在只有 8 台电脑的时候还好,甚至在只有几百台电脑的时候,都还好,所以这种交换机的设计方式,已经足足支撑一阵子了。

  此时你动了歪脑筋,你发现了问题的根本在于,连出去的那根红色的网线,后面不知道有多少个设备不断地连接进来,从而使得地址表越来越大。

  那我可不可以让那根红色的网线,接入一个新的设备,这个设备就跟电脑一样有自己独立的 MAC 地址,而且同时还能帮我把数据包做一次转发呢?

  这个设备就是路由器,它的功能就是,作为一立的拥有 MAC 地址的设备,并且可以帮我把数据包做一次转发,你把它定在了网络层。

  好了,现在交换机的 MAC 地址表中,只需要多出一条 MAC 地址 ABAB 与其端口的映射关系,就可以成功把数据包转交给路由器了,这条搞定。

  那如何做到,把发送给 C 和 D,甚至是把发送给 DEFGH.... 的数据包,统统先发送给路由器呢?

  不难想到这样一个点子,假如电脑 C 和 D 的 MAC 地址拥有共同的前缀,比如分别是:

  那我们就可以说:将目标 MAC 地址为FFFF-FFFF-?开头的,统统先发送给路由器。

  我们先从现实中 MAC 地址的结构入手,MAC地址也叫物理地址、硬件地址,长度为 48 位,一般这样来表示:

  它是由网络设备制造商生产时烧录在网卡的EPROM(一种闪存芯片,通常可以通过程序擦写)。其中前 24 位(00-16-EA)代表网络硬件制造商的编号,后 24 位(AE-3C-40)是该厂家自己分配的,一般表示系列号。只要不更改自己的 MAC 地址,MAC 地址在世界是唯一的。

  那如果你希望向上面那样表示将目标 MAC 地址为FFFF-FFFF-?开头的,统一从路由器出去发给某一群设备(后面会提到这其实是子网的概念),那你就需要要求某一子网下统统买一个厂商制造的设备,要么你就需要要求厂商在生产网络设备烧录 MAC 地址时,提前按照你规划好的子网结构来定 MAC 地址,并且日后这个网络的结构都不能轻易改变。

  现在每一台电脑,同时有自己的 MAC 地址,又有自己的 IP 地址,只不过 IP 地址是软件层面上的,可以随时修改,MAC 地址一般是无法修改的。

  这样一个可以随时修改的 IP 地址,就可以根据你规划的网络拓扑结构,来调整了。

  如上图所示:假如我想要发送数据包给 ABCD 其中一台设备,不论哪一台,我都可以这样描述:将 IP 地址为 192.168.0 开头的全部发送给到路由器,之后再怎么转发,交给它!,巧妙吧。

  现在两个设备之间传输,除了加上数据链路层的头部之外,还要再增加一个网络层的头部。

  假如 A 给 B 发送数据,由于它们直接连着交换机,所以 A 直接发出如下数据包即可,其实网络层没有体现出作用。

  但假如 A 给 C 发送数据,A 就需要先转交给路由器,然后再由路由器转交给 C。由于最底层的传输仍然需要依赖以太网,所以数据包是分成两段的。

  好了,上面说的两种情况(A - B、A - C),相信细心的读者应该会有不少疑问,下面我们一个个来展开。

  路由器的原理也就是我们在上节中提到的那样,路由器看起来好像也没啥了不起的,但事实并非如此。

  实际上,路由器是互联网的主要结点设备,可以这样说:正是路由器构成了互联网的通信骨架。

  正因为如此,对于入门者而言,跟路由器有关的知识点(包括路由原理等)所涉及的疑问,其实会非常多,本节将着重探讨几个重要的方面。

  这两个是我们人为规定的,即我们想表示,对于 192.168.0.1 来说:

  这表示:将源 IP 与目的 IP 分别同这个子网掩码进行与运算,相等则是在一个子网,不相等就是在不同子网,就这么简单。

  那么 A 与 B 在同一个子网,C 与 D 在同一个子网,但是 A 与 C 就不在同一个子网,与 D 也不在同一个子网,以此类推。

  所以:如果 A 给 C 发消息,A 和 C 的 IP 地址分别 & A 机器配置的子网掩码,发现不相等,则 A 认为 C 和自己不在同一个子网,于是把包发给路由器,就不管了,之后怎么转发,A 不关心。

  上章中:A 如何知道,哪个设备是路由器?答案是:在 A 上要设置默认网关。

  上一步 A 通过是否与 C 在同一个子网内,判断出自己应该把包发给路由器,那路由器的 IP 是多少呢?

  对 A 来说,A 只能直接把包发给同处于一个子网下的某个 IP 上,所以发给路由器还是发给某个电脑,对 A 来说也不关心,只要这个设备有个 IP 地址就行。

  所以:默认网关就是 A 在自己电脑里配置的一个 IP 地址,以便在发给不同子网的机器时,发给这个 IP 地址。

  一个问题就是:路由器怎么知道,收到的这个数据包,该从自己的哪个端口出去,才能直接(或间接)地最终到达目的地 C 呢。

  路由器收到的数据包有目的 IP 也就是 C 的 IP 地址,需要转化成从自己的哪个端口出去,很容易想到,应该有个表,就像 MAC 地址表一样。

  至于这个路由表是怎么出来的,有很多路由算法,本文不展开,因为我也不会哈哈 ~

  不同于 MAC 地址表的是,路由表并不是一对一这种明确关系,我们下面看一个路由表的结构。

  我们学习一种新的表示方法,由于子网掩码其实就表示前多少位表示子网的网段,所以如 192.168.0.0(255.255.255.0) 也可以简写为 192.168.0.0/24。

  这就很好理解了:路由表就表示,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 地址的对应关系。

  一开始的时候这个表是空的,电脑 A 为了知道电脑 B(192.168.0.2)的 MAC 地址,将会广播一条 ARP 请求,B 收到请求后,带上自己的 MAC 地址给 A 一个响应。此时 A 便更新了自己的 ARP 表。

  这样通过大家不断广播 ARP 请求,最终所有电脑里面都将 ARP 缓存表更新完整。

  网络层(IP协议)本身没有传输包的功能,包的实际传输是委托给数据链路层(以太网中的交换机)来实现的。

  知道了以上这些,目前网络上两个节点是如何发送数据包的这个过程,就完全可以解释通了!

  这时路由器 1 连接了路由器 2,所以其路由表有了下一条地址这一个概念,所以它的路由表就变成了这个样子。如果匹配到了有下一跳地址的一项,则需要再次匹配,找到其端口,并找到下一跳 IP 的 MAC 地址。

  也就是说找来找去,最终必须能映射到一个端口号,然后从这个端口号把数据包发出去。

  这时:如果 A 给 F 发送一个数据包,能不能通呢?如果通的话整个过程是怎样的呢?

  详细过程文字描述:【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 地址就是自己,于是收下了这个包。

  至此,经过物理层、数据链路层、网络层这前三层的协议,以及根据这些协议设计的各种网络设备(网线、集线器、交换机、路由器),理论上只要拥有对方的 IP 地址,就已经将地球上任意位置的两个节点连通了。

  本文经过了很多次的修改,删减了不少影响主流程的内容,就是为了让读者能抓住网络传输前三层的真正核心思想。同时网络相关的知识也是多且杂,我也还有很多搞不清楚的地方,非常欢迎大家讨论交流,共同进步。

  本文下篇《网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?(稍后发布...)》,敬请期待!

  《网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势》

  《网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门》

  《网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接》

  《网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?》

  《脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?》

  《脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)》

  《脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?》

  《脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?》

  《高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索》

  《从根上理解高性能、高并发(二):深入操作系统,理解I/O与零拷贝技术》

  《从根上理解高性能、高并发(三):深入操作系统,彻底理解I/O多路复用》

  《IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!》

  《IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!》

  《IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!》

  《IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!》