图解网络 — 基础篇
2022-08-12 23:38:39 56 举报
AI智能生成
小林coding 图解网络 基础篇 脑图总结
作者其他创作
大纲/内容
网络模型
网络有 3 种分层模型:
每层对应的工作设备:
每层对应的功能:
每层对应的主要协议:
TCP/IP 网络 4 层模型
应用层
最上层的,也是我们能直接接触到的就是应用层(Application Layer),我们电脑或手机使用的应用软件都是在应用层实现。
应用层只需要专注于为用户提供应用功能,比如 HTTP、FTP、Telnet、DNS、SMTP等。
应用层是不用去关心数据是如何传输的,就类似于,我们寄快递的时候,只需要把包裹交给快递员,<br>由他负责运输快递,我们不需要关心快递是如何被运输的。
应用层是工作在操作系统中的用户态,传输层及以下则工作在内核态。
传输层
应用层的数据包会传给传输层,传输层(Transport Layer)是为应用层提供网络支持的。
在传输层会有两个传输协议,分别是 TCP 和 UDP。
TCP 的全称叫传输控制协议(Transmission Control Protocol),大部分应用使用的正是 TCP 传输层协议,比如 HTTP 应用层协议。<br>TCP 相比 UDP 多了很多特性,比如流量控制、超时重传、拥塞控制等,这些都是为了保证数据包能可靠地传输给对方。
UDP 相对来说就很简单,简单到只负责发送数据包,不保证数据包是否能抵达对方,但它实时性相对更好,传输效率也高。当然,<br>UDP 也可以实现可靠传输,把 TCP 的特性在应用层上实现就可以,不过要实现一个商用的可靠 UDP 传输协议,也不是一件简单的事情。
应用需要传输的数据可能会非常大,如果直接传输就不好控制,因此当传输层的数据包大小超过 MSS(TCP 最大报文段长度) ,<br>就要将数据包分块,这样即使中途有一个分块丢失或损坏了,只需要重新发送这一个分块,而不用重新发送整个数据包。<br>在 TCP 协议中,我们把每个分块称为一个 <font color="#ff0000">TCP 段</font>(TCP Segment)。
当设备作为接收方时,传输层则要负责把数据包传给应用,但是一台设备上可能会有很多应用在接收或者传输数据,<br>因此需要用一个编号将应用区分开来,这个编号就是<font color="#ff0000">端口</font>。
比如 80 端口通常是 Web 服务器用的,22 端口通常是远程登录服务器用的。而对于浏览器(客户端)<br>中的每个标签栏都是一个独立的进程,操作系统会为这些进程分配临时的端口号。
由于 <b>传输层的报文中会携带端口号</b>,因此 <b>接收方可以识别出该报文是发送给哪个应用</b>。
网络层
传输层可能大家刚接触的时候,会认为它负责将数据从一个设备传输到另一个设备,事实上它并不负责。<br>我们不希望传输层协议处理太多的事情,只需要服务好应用即可,让其作为应用间数据传输的媒介,帮助<br>实现应用到应用的通信,而实际的传输功能就交给下一层,也就是 <font color="#ff0000">网络层</font>(Internet Layer)。<br>
网络层最常使用的是 IP 协议(Internet Protocol),IP 协议会将传输层的报文作为数据部分,再加上 IP 包头组装成 IP 报文,<br>如果 IP 报文大小超过 MTU(以太网中一般为 1500 字节)就会 <b>再次进行分片</b>,得到一个即将发送到网络的 IP 报文。
网络层负责将数据从一个设备传输到另一个设备,世界上那么多设备,又该如何找到对方呢?因此,网络层需要有区分设备的编号。
IP 地址
一般用 IP 地址给设备进行编号,对于 IPv4 协议, IP 地址共 32 位,分成了四段(比如,192.168.100.1),每段是 8 位。<br>只有一个单纯的 IP 地址虽然做到了区分设备,但是寻址起来就特别麻烦,全世界那么多台设备,难道一个一个去匹配?这显然不科学。
因此,需要将 IP 地址分成两种意义:<br><ul><li>一个是网络号,负责标识该 IP 地址是属于哪个「子网」的;</li><li>一个是主机号,负责标识同一「子网」下的不同主机;</li></ul>
怎么分的呢?这需要配合 <b>子网掩码 </b>才能算出 IP 地址 的网络号和主机号。<br>比如 10.100.122.0/24,后面的 /24 表示就是 255.255.255.0 的子网掩码,255.255.255.0 <br>二进制是「11111111-11111111-11111111-00000000」,共有 24 个1,为了简化子网<br>掩码的表示,用 /24 代替 255.255.255.0。
知道了子网掩码,该怎么计算出网络地址和主机地址呢?<br>将 10.100.122.2 和 255.255.255.0 进行按位与运算,就可以得到网络号,如下图。<br>将 255.255.255.0 取反后与IP地址进行进行按位与运算,就可以得到主机号。<br>
那么在寻址的过程中,先匹配到相同的网络号(表示要找到同一个子网),才会去找对应的主机。
除了寻址能力, IP 协议还有另一个重要的能力就是 <b>路由</b>。实际场景中,两台设备并不是用一条网线连接起来的,而是通过很多网关、路由器、交换机<br>等众多网络设备连接起来的,那么就会形成很多条网络的路径,因此当数据包到达一个网络节点,就需要通过路由算法决定下一步走哪条路径。
路由器寻址工作中,就是要找到目标地址的子网,找到后进而把数据包转发给对应的网络内。
所以,<b>IP 协议的寻址作用是告诉我们去往下一个目的地该朝哪个方向走,路由则是根据「下一个目的地」选择路径。<br>寻址更像在导航,路由更像在操作方向盘。</b>
网络接口层
生成了 IP 头部之后,接下来要交给 <b>网络接口层</b>(Link Layer)在 IP 头部的前面加上 MAC 头部,<br>并封装成数据帧(Data frame)发送到网络上。
IP 头部中的接收方 IP 地址表示网络包的目的地,通过这个地址我们就可以判断要将包发到哪里,<br>但在以太网的世界中,这个思路是行不通的。
什么是以太网?电脑上的以太网接口,Wi-Fi接口,以太网交换机、路由器上的千兆,万兆以太网口,还有网线,<br>它们都是以太网的组成部分。以太网就是一种在「局域网」内,把附近的设备连接起来,使它们之间可以进行通讯的技术。
以太网在判断网络包目的地时和 IP 的方式不同,因此必须采用相匹配的方式才能在以太网中将包发往目的地,<br>而 MAC 头部就是干这个用的,所以,在以太网进行通讯要用到 MAC 地址。
MAC 头部是以太网使用的头部,它包含了接收方和发送方的 MAC 地址等信息,<br>我们可以通过 ARP 协议获取对方的 MAC 地址。
所以说,网络接口层主要为网络层提供「链路级别」传输的服务,负责在以太网、WiFi 这样的底层网络上发送原始数据包,<br>工作在网卡这个层次,使用 MAC 地址来标识网络上的设备。
总结
TCP/IP 网络通常是由上到下分成 4 层,分别是应用层,传输层,网络层和网络接口层。
每一层的封装格式:
网络接口层的传输单位是帧(frame),IP 层的传输单位是包(packet),TCP 层的传输单位是段(segment),<br>HTTP 的传输单位则是消息或报文(message)。但这些名词并没有什么本质的区分,可以统称为数据包。
键入网址到网页显示,期间发生了什么?
以下图较简单的网络拓扑模型作为例子,探究探究其间发生了什么?
孤单小弟 — HTTP
浏览器做的 <b><font color="#0000ff">第一步工作是解析 URL</font></b>
首先浏览器做的第一步工作就是要对 URL 进行解析,从而生成发送给 Web 服务器的请求信息。
一条长长的 URL 里的各个元素实际上是请求服务器里的文件资源,见下图:
如果上图中的蓝色部分 URL 元素都省略了,当没有路径名时,就代表访问根目录下事先设置的默认文件,<br>也就是 /index.html 或者 /default.html 这些文件,这样就不会发生混乱了。
<b><font color="#0000ff">产生 HTTP 请求信息</font></b>
对 URL 进行解析之后,浏览器确定了 Web 服务器和文件名,接下来就是根据这些信息来生成 HTTP 请求消息了。
一个孤单 HTTP 数据包表示:“我这么一个小小的数据包,没亲没友,直接发到浩瀚的网络,谁会知道我呢?谁能载我一程呢?<br>谁能保护我呢?我的目的地在哪呢?”。充满各种疑问的它,没有停滞不前,选择继续踏上茫茫征途,继续探索!
真实地址查询 — DNS
DNS 的由来
通过浏览器解析 URL 并生成 HTTP 消息后,需要委托操作系统将消息发送给 Web 服务器。
但在发送之前,还有一项工作需要完成,那就是 <font color="#0000ff"><b>查询服务器域名对应的 IP 地址</b></font>,<br>因为委托操作系统发送消息时,必须提供通信对象的 IP 地址。
所以,有一种服务器就专门 <b><font color="#0000ff">保存了 Web 服务器域名与 IP 的对应关系</font></b>,它就是<font color="#0000ff"> <b>DNS 服务器</b></font>。
域名的层级关系
DNS 中的域名都是用句点来分隔的,比如 www.server.com,这里的句点代表了不同层次之间的界限。<br>在域名中,<b><font color="#0000ff">越靠右</font> </b>的位置表示其 <b><font color="#0000ff">层级越高</font></b>。<br>
实际上域名最后还有一个点,比如 www.server.com.,这个最后的一个点代表根域名。<br><br>也就是,. 根域是在最顶层,它的下一层就是 .com 顶级域,再下面是 server.com。
所以域名的层级关系类似一个树状结构:<br><ul><li>根 DNS 服务器(.)</li><li>顶级域 DNS 服务器(.com)</li><li>权威 DNS 服务器(server.com)</li></ul>
根域的 DNS 服务器信息保存在互联网中所有的 DNS 服务器中。<br><br>这样一来,任何 DNS 服务器就都可以找到并访问根域 DNS 服务器了。<br><br>因此,客户端只要能够找到任意一台 DNS 服务器,就可以通过它找到根域 DNS 服务器,<br>然后再一路顺藤摸瓜找到位于下层的某台目标 DNS 服务器。
<b><font color="#0000ff">域名解析 </font></b>的工作流程<br>
1. 客户端首先会发出一个 DNS 请求,问 www.server.com 的 IP 是啥,并发给本地 DNS 服务器<br> (也就是客户端的 TCP/IP 设置中填写的 DNS 服务器地址)。
2. 本地域名服务器收到客户端的请求后,如果 <b><font color="#0000ff">缓存里</font> </b>的表格能找到 www.server.com,则它直接返回 IP 地址。<br> 如果没有,<b><font color="#0000ff">本地 DNS 会去问它的根域名服务器</font></b>:“老大, 能告诉我 www.server.com 的 IP 地址吗?” <br><b> <font color="#0000ff">根域名服务器是最高层次的,它不直接用于域名解析,但能指明一条道路</font></b>。
3. 根 DNS 收到来自本地 DNS 的请求后,发现后置是 .com,说:“www.server.com 这个域名归 .com 区域管理”,<br> 我给你 .com 顶级域名服务器地址给你,你去问问它吧。”
4. 本地 DNS 收到顶级域名服务器的地址后,发起请求问“老二, 你能告诉我 www.server.com 的 IP 地址吗?”
5. 顶级域名服务器说:“我给你负责 www.server.com 区域的权威 DNS 服务器的地址,你去问它应该能问到”。
6. 本地 DNS 于是转向问权威 DNS 服务器:“老三,www.server.com对应的IP是啥呀?” <br> server.com 的权威 DNS 服务器,它是域名解析结果的原出处。为啥叫权威呢?就是我的域名我做主。
7. 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。
8. 本地 DNS 再将 IP 地址返回客户端,客户端和目标建立连接。
图解:
DNS 域名解析的过程蛮有意思的,整个过程就和我们日常生活中找人问路的过程类似,<b><font color="#0000ff">只指路不带路</font></b>。
是不是每次解析域名都要经过那么多的步骤呢?
当然不是了,还有缓存这个东西的嘛。<br><br>浏览器会 <b>先看自身有没有对这个域名的 <font color="#0000ff">缓存</font></b>,如果有,就直接返回,如果没有,就 <b><font color="#0000ff">去问操作系统</font></b>,操作系统也会去<br>看自己的缓存,如果有,就直接返回,如果没有,<b><font color="#0000ff">再去 hosts 文件看</font></b>,也没有,<b><font color="#0000ff">才会去问「本地 DNS 服务器」</font></b>。
数据包表示:“DNS 老大哥厉害呀,找到了目的地了!我还是很迷茫呀,我要发出去,接下来我需要谁的帮助呢?”
指南好帮手 — 协议栈
通过 DNS 获取到 IP 后,就可以把 HTTP 的传输工作交给操作系统中的 <b>协议栈</b>。
协议栈的内部分为几个部分,分别承担不同的工作。上下关系是有一定的规则的,<br>上面的部分会向下面的部分委托工作,下面的部分收到委托的工作并执行。
应用程序(浏览器)通过调用 Socket 库,来委托协议栈工作。协议栈的上半部分有两块,<br>分别是负责收发数据的 TCP 和 UDP 协议,这两个传输协议会接受应用层的委托执行收发数据的操作。
协议栈的下半部分是用 IP 协议控制网络包收发操作,在互联网上传数据时,数据会被切分成一块块的网络包,<br>而将网络包发送给对方的操作就是由 IP 负责的。
此外 IP 中还包括 ICMP 协议和 ARP 协议:<br><ul><li>ICMP 用于告知网络包传送过程中产生的错误以及各种控制信息。</li><li>ARP 用于根据 IP 地址查询相应的以太网 MAC 地址。</li></ul>
IP 下面的网卡驱动程序负责控制网卡硬件,而最下面的网卡则负责完成实际的收发操作,<br>也就是对网线中的信号执行发送和接收操作。
数据包看了这份指南表示:“原来我需要那么多大佬的协助啊,那我先去找找 TCP 大佬!”<br>
可靠传输 — TCP
HTTP 是基于 TCP 协议传输的,所以在这我们先了解下 TCP 协议。
TCP 包头格式
TCP 报文头部的格式:
首先,<b>源端口号 </b>和 <b>目标端口号</b> 是不可少的,如果没有这两个端口号,数据就不知道 <b>应该发给哪个应用</b>。
接下来有包的 <b>序号</b>,这个是为了 <b>解决包乱序的问题</b>。
还应该有的是 <b>确认号</b>,目的是确认发出去对方是否有收到。如果没有收到就应该重新发送,<br>直到送达,这个是为了 <b>解决不丢包的问题</b>。
接下来还有一些 <b>状态位</b>。例如 SYN 是发起一个连接,ACK 是回复,RST 是重新连接,FIN 是结束连接等。<br>TCP 是面向连接的,因而 <b>双方要维护连接的状态</b>,这些带状态位的包的发送,会引起双方的状态变更。
还有一个重要的就是 <b>窗口大小</b>。TCP 要做 <b>流量控制</b>,通信双方各声明一个窗口(缓存大小),<br>标识自己当前能够的处理能力,别发送的太快,撑死我,也别发的太慢,饿死我。
除了做流量控制以外,TCP还会做 <b>拥塞控制</b>,对于真正遇到通路堵车,它无能为力,<br>唯一能做的就是控制自己,也即 <b>控制发送的速度</b>。不能改变世界,就改变自己嘛。
<b>TCP 传输数据之前,要先三次握手建立连接</b>
在 HTTP 传输数据之前,首先需要 TCP 建立连接,TCP 连接的建立,通常称为 <b>三次握手</b>。
这个所谓的「连接」,只是双方计算机里维护一个状态机,在连接建立的过程中,双方的状态变化时序图就像这样。<br>
一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态。
然后客户端主动发起连接 SYN,之后处于 SYN-SENT 发送状态。
服务端收到发起的连接,返回 SYN,并且 ACK 客户端的 SYN,之后处于 SYN-RCVD 接收状态。
客户端收到服务端发送的 SYN 和 ACK 之后,发送对 SYN 确认的 ACK,<br>之后处于 ESTABLISHED 已确立状态,因为它一发一收成功了。
服务端收到客户端对 SYN 确认的 ACK 之后,处于 ESTABLISHED 已确立状态,因为它也一发一收了。
所以三次握手目的是 <b>保证双方都有发送和接收的能力</b>。<br>
如何查看 TCP 的连接状态?
TCP 的连接状态查看,在 Linux 可以通过 netstat -napt 命令查看。
TCP 分割数据
如果 HTTP 请求消息比较长,超过了 MSS 的长度,这时 TCP 就需要把 HTTP 的数据<br>拆解成一块块的数据发送,而不是一次性发送所有数据。<br><ul><li>MTU:一个网络包的最大长度,以太网中一般为 1500 字节。</li><li>MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度。</li></ul>
数据会被以 MSS 的长度为单位进行拆分,拆分出来的每一块数据都会被放进单独的网络包中。<br>也就是在每个被拆分的数据加上 TCP 头信息,然后交给 IP 模块来发送数据。
TCP 报文生成<br>
TCP 协议里面会有两个端口,一个是浏览器监听的端口(通常是随机生成的),一个<br>是 Web 服务器监听的端口(HTTP 默认端口号是 80, HTTPS 默认端口号是 443)。
在双方建立了连接后,TCP 报文中的数据部分就是存放 HTTP 头部 + 消息体,<br>组装好 TCP 报文之后,就需交给下面的网络层处理。
至此,网络包的报文如下图:<br>
此时,遇上了 TCP 的 数据包激动表示:“太好了,碰到了可靠传输的 TCP 传输,它给我加上 TCP 头部,<br>我不再孤单了,安全感十足啊!有大佬可以保护我的可靠送达!但我应该往哪走呢?”
远程地位 — IP
TCP 模块在执行连接、收发、断开等各阶段操作时,都需要委托 IP 模块将数据封装成 <b>网络包 </b>发送给通信对象。
IP 包头格式<br>
IP 报文头部的格式:
在 IP 协议里面需要有源地址 IP 和 目标地址 IP:<br><ul><li>源地址IP,即是客户端输出的 IP 地址;</li><li>目标地址,即通过 DNS 域名解析得到的 Web 服务器 IP。<br></li></ul>
因为 HTTP 是经过 TCP 传输的,所以在 IP 包头的协议号,要填写为 06(十六进制),表示协议为 TCP。
假设客户端有多个网卡,就会有多个 IP 地址,那 IP 头部的 <b>源地址 </b>应该选择哪个 IP 呢?
这个判断相当于在多块网卡中判断应该使用哪个一块网卡来发送包。<br>这个时候就需要根据路由表规则,来判断哪一个网卡作为源地址 IP。<br>
在 Linux 操作系统,我们可以使用 route -n 命令查看当前系统的路由表。
举个例子,根据上面的路由表,我们假设 Web 服务器的 <b>目标地址 </b>是 192.168.10.200。
首先先和第一条目的地的子网掩码(Genmask)进行 <b>与运算</b>,得到结果为 192.168.10.0,<br>但是第一个条目的地 Destination 是 192.168.3.0,两者不一致所以匹配失败。
再与第二条目的地的子网掩码进行 <b>与运算</b>,得到的结果为 192.168.10.0,与第二条目的地<br>Destination 192.168.10.0 匹配成功,所以将使用 eth1 网卡的 IP 地址作为 IP 包头的源地址。
第三条目比较特殊,它目标地址和子网掩码都是 0.0.0.0,这表示 <b>默认网关</b>,如果其他所有条目都无法匹配,<br>就会自动匹配这一行。并且后续就把包发给路由器,Gateway 即是路由器的 IP 地址。
IP 报文生成<br>
至此,网络包的报文如下图:
此时,加上了 IP 头部的数据包表示 :“有 IP 大佬给我指路了,感谢 IP 层给我加上了 IP 包头,<br>让我有了远程定位的能力!不会害怕在浩瀚的互联网迷茫了!可是目的地好远啊,我下一站应该去哪呢?”
两点传输 — MAC
生成了 IP 头部之后,接下来网络包还需要在 IP 头部的前面加上 MAC 头部。
MAC 包头格式<br>
MAC 头部是以太网使用的头部,它包含了接收方和发送方的 MAC 地址等信息。
在 MAC 包头里需要 <b>发送方 MAC 地址 </b>和 <b>接收方目标 MAC 地址</b>,用于 <b>两点之间的传输</b>。
一般在 TCP/IP 通信里,MAC 包头的 <b>协议类型 </b>只使用:<br><ul><li>0800 : IP 协议</li><li>0806 : ARP 协议</li></ul>
MAC 发送方和接收方如何确认?<br>
发送方的 MAC 地址获取就比较简单了,MAC 地址是在网卡生产时写入到 ROM 里的,<br>只要将这个值读取出来写入到 MAC 头部就可以了。
接收方的 MAC 地址就有点复杂了,只要告诉以太网对方的 MAC 的地址,<br>以太网就会帮我们把包发送过去,那么很显然这里应该填写对方的 MAC 地址。
所以先得搞清楚应该把包发给谁,这个只要查一下路由表就知道了。在路由表<br>中找到相匹配的条目,然后把包发给 Gateway 列中的 IP 地址就可以了。
<b>既然知道要发给谁,按如何获取对方的 MAC 地址呢?</b><br>
不知道对方 MAC 地址?不知道就喊呗。<br><br>此时就需要 ARP 协议帮我们找到路由器的 MAC 地址。
ARP 协议会在以太网中以 <b>广播</b> 的形式,对以太网所有的设备喊出:“这个 IP 地址是谁的?请把你的 MAC 地址告诉我”。<br><br>然后就会有人回答:“这个 IP 地址是我的,我的 MAC 地址是 XXXX”。<br><br>如果对方和自己处于同一个子网中,那么通过上面的操作就可以得到对方的 MAC 地址。<br>然后,我们将这个 MAC 地址写入 MAC 头部,MAC 头部就完成了。
<b>好像每次都要广播获取,这不是很麻烦吗?</b><br>放心,在后续操作系统会把本次查询结果放到一块叫做 ARP 缓存的内存空间留着以后用,不过缓存的时间就几分钟。<br><br>也就是说,在发包时:<br><ul><li>先查询 ARP 缓存,如果其中已经保存了对方的 MAC 地址,就不需要发送 ARP 查询,直接使用 ARP 缓存中的地址。</li><li>而当 ARP 缓存中不存在对方 MAC 地址时,则发送 ARP 广播查询。</li></ul>
在 Linux 系统中,我们可以使用 arp -a 命令来查看 ARP 缓存的内容。<br>
MAC 报文生成<br>
至此,网络包的报文如下图:
此时,加上了 MAC 头部的数据包万分感谢,说道 :“感谢 MAC 大佬,我知道我下一步要去哪了!<br>我现在有很多头部兄弟,相信我可以到达最终的目的地!”。 带着众多头部兄弟的数据包,终于准备要出门了。
出口 — 网卡
网络包只是存放在内存中的一串二进制数字信息,没有办法直接发送给对方。因此,我们<br>需要将 <b>数字信息转换为电信号</b>,才能在网线上传输,也就是说,这才是真正的数据发送过程。
负责执行这一操作的是 <b>网卡</b>,要控制网卡还需要靠 <b>网卡驱动程序</b>。
网卡驱动获取网络包之后,会将其 <b>复制 </b>到网卡内的缓存区中,接着会在<br>其 <b>开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列</b>。<br><ul><li>起始帧分界符是一个用来表示包起始位置的标记</li><li>末尾的 FCS(帧校验序列)用来检查包传输过程是否有损坏</li></ul>
最后网卡会将包转为电信号,通过网线发送出去。<br>
唉,真是不容易,发一个包,真是历经千辛万苦。致此,一个带有许多头部的数据包终于踏上寻找目的地的征途了!
送别者 — 交换机
下面来看一下包是如何通过交换机的。交换机的设计是将网络包 <b>原样 </b>转发到目的地。<br>交换机工作在 MAC 层,也称为 <b>二层网络设备</b>。
交换机的包接收操作<br>
首先,电信号到达网线接口,交换机里的模块进行接收,接下来交换机里的模块将电信号转换为数字信号。
然后通过包末尾的 FCS 校验错误,如果没问题则放到缓冲区。<br>这部分操作基本和计算机的网卡相同,但交换机的工作方式和网卡不同。
<ul><li>计算机的网卡本身具有 MAC 地址,并通过核对收到的包的接收方 MAC <br>地址判断是不是发给自己的,如果不是发给自己的则丢弃;</li><li>相对地,<b>交换机的端口不核对接收方 MAC 地址</b>,而是 <b>直接接收所有的<br>包并存放到缓冲区中</b><b>包并存放到缓冲区中</b>。</li><li>因此,和网卡不同,<b>交换机的端口不具有 MAC 地址</b>。</li></ul>
将包存入缓冲区后,接下来需要查询一下这个包的接收方 MAC 地址是否已经在 MAC 地址表中有记录了。
交换机的 MAC 地址表主要包含两个信息:<br><ul><li>一个是设备的 MAC 地址</li><li>另一个是该设备连接在交换机的哪个端口上</li></ul>
举个例子,如果收到的包的接收方 MAC 地址为 00-02-B3-1C-9C-F9,则与图中表中的第 3 行匹配,<br>根据端口列的信息,可知这个地址位于 3 号端口上,然后就可以通过交换电路将包发送到相应的端口了。
所以,<b>交换机根据 MAC 地址表查找 MAC 地址,然后将信号发送到相应的端口</b>。
当 MAC 地址表找不到指定的 MAC 地址会怎么样?<br>
地址表中找不到指定的 MAC 地址。这可能是因为具有该地址的设备还没有向交换机发送过包,<br>或者这个设备一段时间没有工作导致地址被从地址表中删除了。<br><br>这种情况下,交换机无法判断应该把包转发到哪个端口,只能将包转发到<b>除了源端口之外的所有端口上</b>,<br>无论该设备连接在哪个端口上都能收到这个包。
这样做不会产生什么问题,因为以太网的设计本来就是将包发送到整个网络的,<br>然后 <b>只有相应的接收者才接收包,而其他设备则会忽略这个包。</b>
这样做会发送多余的包,会不会造成网络拥塞呢?
其实完全不用过于担心,因为发送了包之后目标设备会作出响应,只要返回了响应包,<br>交换机就可以将它的地址写入 MAC 地址表,下次也就不需要把包发到所有端口了。
局域网中每秒可以传输上千个包,多出一两个包并无大碍。<br>
此外,如果接收方 MAC 地址是一个 <b>广播地址</b>,那么交换机会将包发送到除源端口之外的所有端口。<br><br>以下两个属于广播地址:<br><ul><li>MAC 地址中的 FF:FF:FF:FF:FF:FF</li><li>IP 地址中的 255.255.255.255</li></ul>
数据包通过交换机转发抵达了路由器,准备要离开土生土长的子网了。此时,数据包<br>和交换机离别时说道:“感谢交换机兄弟,帮我转发到出境的大门,我要出远门啦!”
出境大门 — 路由器
路由器与交换机的区别<br>
网络包经过交换机之后,现在到达了 <b>路由器</b>,并在此被转发到下一个路由器或目标设备。
这一步转发的工作原理和交换机类似,也是通过查表判断包转发的目标。<br><br>不过在具体的操作过程上,路由器和交换机是有区别的:<br><ul><li>因为路由器是基于 IP 设计的,俗称三层网络设备,路由器的各个端口都具有 MAC 地址和 IP 地址;</li><li>而交换机是基于以太网设计的,俗称二层网络设备,交换机的端口不具有 MAC 地址。</li></ul>
路由器基本原理<br>
路由器的端口具有 MAC 地址,因此它就能够成为以太网的发送方和接收方;<br>同时还具有 IP 地址,从这个意义上来说,它和计算机的网卡是一样的。
当转发包时,首先路由器端口会接收发给自己的以太网包,然后 <b>路由表 </b>查询转发目标,<br>再由相应的端口作为发送方将以太网包发送出去。
路由器的包接收操作<br>
首先,电信号到达网线接口部分,路由器中的模块会将电信号转成数字信号,<br>然后通过包末尾的 FCS 进行错误校验。
如果没问题则检查 MAC 头部中的 <b>接收方 MAC 地址</b>,看看是不是发给自己的包,<br>如果是就放到接收缓冲区中,否则就丢弃这个包。
总的来说,路由器的端口都具有 MAC 地址,只接收与自身地址匹配的包,遇到不匹配的包则直接丢弃。
查询路由表确定输出端口<br>
完成包接收操作之后,路由器就会 <b>去掉 </b>包开头的 <b>MAC 头部</b>。
<b>MAC 头部的作用就是将包送达路由器</b>,其中的接收方 MAC 地址就是路由器端口的 MAC 地址。<br>因此,当包到达路由器之后,MAC 头部的任务就完成了,于是 <b>MAC 头部就会被丢弃</b>。
接下来,路由器会根据 MAC 头部后方的 <b>IP 头部 </b>中的内容进行包的转发操作。
转发操作分为几个阶段,首先是 <b>查询路由表 </b>判断转发目标。具体地流程如下图:
假设地址为 10.10.1.101 的计算机要向地址为 192.168.1.100 的服务器发送一个包,这个包先到达图中的路由器。
判断转发目标的第一步,就是根据包的接收方 IP 地址查询路由表中的目标地址栏,以找到相匹配的记录。
路由匹配和前面讲 IP 的匹配一样,每个条目的 <b>子网掩码和 192.168.1.100 IP 做 & 与运算 </b>后,得到的结果与对应<br>条目的目标地址进行匹配,如果匹配就会作为候选转发目标,如果不匹配就继续与下个条目进行路由匹配。<br>
如第二条目的子网掩码 255.255.255.0 与 192.168.1.100 IP 做 & 与运算后,得到结果是 192.168.1.0 ,<br>这与第二条目的目标地址 192.168.1.0 匹配,该第二条目记录就会被作为转发目标。
实在找不到匹配路由时,就会选择默认路由,路由表中子网掩码为 0.0.0.0 的记录表示「默认路由」。
路由器的发送操作<br>
接下来就会进入包的 <b>发送操作</b>。<br><br>首先,我们需要根据 <b>路由表的网关列 </b>判断对方的地址。<br><ul><li>如果网关是一个 IP 地址,则这个IP 地址就是我们要转发到的目标地址,<br>还未抵达终点,还需继续需要路由器转发。</li><li>如果网关为空,则 IP 头部中的接收方 IP 地址就是要转发到的目标地址,<br>也是就终于找到 IP 包头里的目标地址了,说明已抵达终点。</li></ul>
知道对方的 IP 地址之后,接下来需要通过 ARP 协议根据 IP 地址查询 MAC 地址,并将查询的结果作为接收方 MAC 地址。
路由器也有 ARP 缓存,因此首先会在 ARP 缓存中查询,如果找不到则发送 ARP 查询请求。<br>
接下来是发送方 MAC 地址字段,这里填写输出端口的 MAC 地址。<br>还有一个以太类型字段,填写 0800 (十六进制)表示 IP 协议。
网络包完成后,接下来会将其转换成电信号并通过端口发送出去。这一步的工作过程和计算机也是相同的。
发送出去的网络包会通过 <b>交换机 </b>到达下一个路由器。由于接收方 MAC 地址就是<br>下一个路由器的地址,所以交换机会根据这一地址将包传输到下一个路由器。
接下来,下一个路由器会将包转发给再下一个路由器,经过层层转发之后,网络包就到达了最终的目的地。
在网络包传输的过程中,<b>源 IP 和目标 IP 始终是不会变的</b>,<b>一直变化的是 MAC 地址</b>,<br>因为需要 MAC 地址在以太网内进行 <b>两个设备 </b>之间的包传输。
数据包通过多个路由器道友的帮助,在网络世界途经了很多路程,最终抵达了目的地的城门!<br>城门值守的路由器,发现了这个小兄弟数据包原来是找城内的人,于是它就将数据包送进了城内,<br>再经由城内的交换机帮助下,最终转发到了目的地了。数据包感慨万千的说道:“多谢这一路上,各路大侠的相助!”
互相扒皮 — 服务器与客户端
数据包抵达了服务器,服务器肯定高兴呀,正所谓有朋自远方来,不亦乐乎?
服务器高兴的不得了,于是开始扒数据包的皮!就好像你收到快递,能不兴奋吗?
数据包抵达服务器后,服务器会先扒开数据包的 MAC 头部,查看是否和服务器自己的 MAC 地址符合,符合就将包收起来。
接着继续扒开数据包的 IP 头,发现 IP 地址符合,根据 IP 头中协议项,知道自己上层是 TCP 协议。<br>
于是,扒开 TCP 的头,里面有序列号,需要看一看这个序列包是不是我想要的,如果是就放入缓存中<br>然后返回一个 ACK,如果不是就丢弃。TCP头部里面还有端口号, HTTP 的服务器正在监听这个端口号。
于是,服务器自然就知道是 HTTP 进程想要这个包,于是就将包发给 HTTP 进程。
服务器的 HTTP 进程看到,原来这个请求是要访问一个页面,于是就把这个网页封装在 HTTP 响应报文里。
HTTP 响应报文也需要穿上 TCP、IP、MAC 头部,不过这次是源地址是<br>服务器 IP 地址,目的地址是客户端 IP 地址。
穿好头部衣服后,从网卡出去,交由交换机转发到出城的路由器,路由器就<br>把响应数据包发到了下一个路由器,就这样跳啊跳。
最后跳到了客户端的城门把守的路由器,路由器扒开 IP 头部发现是要找城内的人,<br>于是又把包发给了城内的交换机,再由交换机转发到客户端。
客户端收到了服务器的响应数据包后,同样也非常的高兴,客户能拆快递了!<br><br>于是,客户端开始扒皮,把收到的数据包的皮扒剩 HTTP 响应报文后,交给浏览器<br>去渲染页面,一份特别的数据包快递,就这样显示出来了!
最后,客户端要离开了,向服务器发起了 TCP 四次挥手,至此双方的连接就断开了。<br>
一个数据包(我)凑不要脸的感受
我一开始我虽然孤单、不知所措,但没有停滞不前。我依然满怀信心和勇气开始了征途。<br>(你当然有勇气,你是应用层数据,后面有底层兄弟当靠山,我呸!)
我很庆幸遇到了各路神通广大的大佬,有可靠传输的 TCP、有远程定位功能的 IP、<br>有指明下一站位置的 MAC 等(你当然会遇到,因为都被计算机安排好的,我呸!)。
这些大佬都给我前面加上了头部,使得我能在交换机和路由器的转发下,<br>抵达到了目的地!(哎,你也不容易,不吐槽了,放过你!)
这一路上的经历,让我认识到了网络世界中各路大侠协作的重要性,是他们<br>维护了网络世界的秩序,感谢他们!(我呸,你应该感谢众多计算机科学家!)
键入 www.baidu.com 流程(简短版)
<b><font color="#d32f2f">浏览器解析 URL,产生 HTTP 请求信息</font></b><br>
请求报文中包含请求方式、使用的协议,协议版本,数据内容等
<b><font color="#f57c00">域名解析,通过 DNS 服务器将域名解析成 IP 地址</font></b>
<span style="font-size: inherit;"><b><font color="#0000ff">域名解析查询顺序</font></b>:<br></span><br><span style="font-size: inherit;">1. 先查看自身的缓存;</span><br><span style="font-size: inherit;">2. 操作系统中的缓存;</span><br><span style="font-size: inherit;">3. hosts 文件中;</span><br><span style="font-size: inherit;">4. 访问本地 DNS 服务器;</span><br>
DNS 查询流程:<b><font color="#0000ff">从根域开始一次往下询问</font></b>。
<font color="#fbc02d"><b>建立 TCP 连接,生成 TCP 报文</b></font>
HTTP 是基于 TCP 协议传输的,所以需要先通过 <b><font color="#0000ff">三次握手建立 TCP 连接</font></b>。
如果 HTTP 请求消息比较长,超过了 MSS 的长度,<b><font color="#0000ff">TCP 就会把 HTTP 的数据拆解成一块一块的数据发送</font></b>。<br>(MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度)
拆分完成后,<b><font color="#0000ff">在每块数据块的首部添加 TCP 头部</font></b>,然后交给 IP 模块来发送数据。<br>(TCP 头部存放源端口号,目的端口号以及 TCP 相关的标志位。TCP 数据部分存放的就是 HTTP 报文)
<b><font color="#388e3c">IP模块 将数据块封装成网络包,生成 IP 报文,发送给通信对象</font></b>
<span style="font-size: inherit;">在 IP 协议里需要有 <b><font color="#0000ff">源 IP 地址和目标 IP 地址</font></b>:</span><br><ul><li><span style="font-size: inherit;">源地址 IP:客户端的 IP 地址;</span></li><li><span style="font-size: inherit;">目标地址 IP:通过 DNS 域名解析得到的 Web 服务器的 IP;</span></li></ul>
生成 IP 头部,添加到 TCP 头部前面,形成 IP 报文。
<b><font color="#0097a7">在 IP 头部前面加上 MAC 头部,生成 MAC 报文</font></b>
在 MAC 包头里需要 <b><font color="#0000ff">发送方 MAC 地址 和 接收方目标 MAC 地址</font></b>,用于 <b><font color="#0000ff">两点之间的传输</font></b>。
发送方的 MAC 地址就在网卡里,读出来就行了,<b><font color="#0000ff">接收方的 MAC 地址需要使用 ARP 协议获取</font></b>。<br>(ARP 也有缓存,缓存中查不到就会以广播的形式询问某个 IP 地址的 MAC 地址)
生成 MAC 头部,添加到 IP 头部前面。
<b>经过层层封装,完整的请求报文已经生成完毕,要开始在网络中传送了</b>
<b><font color="#1976d2">网卡在报文前面加上报头和起始帧分界符,使报文成为帧,能够在网络中传输</font></b>
<b><font color="#0d47a1">交换机根据 MAC 地址将数据包转发至路由器</font></b>
交换机工作在 MAC 层,它将网络包 <b><font color="#0000ff">原样</font></b> 转发到目的地。<br>
<b><font color="#0000ff">交换机根据 MAC 地址表查找 MAC 地址,然后将报文发送到相应的端口。</font></b>
数据包通过交换机转发最终会抵达路由器。
<b><font color="#4a148c">路由器去掉 MAC 头部,根据 IP 头部进行包的转发</font></b>
<b><font color="#0000ff">MAC 头部的作用就是将包送达路由器</font></b>,其中的接收方 MAC 地址就是路由器端口的 MAC 地址。<br>因此,当包到达路由器之后,MAC 头部的任务就完成了,于是 <b><font color="#0000ff">MAC 头部就会被丢弃</font></b>。
接下来,路由器会根据 MAC 头部后方的<b><font color="#0000ff"> IP 头部</font></b> 中的内容进行包的转发操作(查询路由器表)。
知道了对方的 IP 地址后,<b><font color="#0000ff">又要通过 ARP 协议查询对应的 MAC 地址,然后将数据包继续转发给另一个交换机</font></b>。<br>(路由器也有 ARP 缓存,因此也会先查 ARP 缓存,查不到再发送 ARP 查询请求)
发送出去的网络包会通过 <b><font color="#0000ff">交换机</font></b> 到达下一个路由器。由于接收方 MAC 地址就是<br>下一个路由器的地址,所以交换机会根据这一地址将包传输到下一个路由器。
接下来,下一个路由器会将包转发给再下一个路由器,经过层层转发之后,网络包就到达了最终的目的地。
在网络包传输的过程中,<b><font color="#0000ff">源 IP 和目标 IP 始终是不会变的,一直变化的是 MAC 地址</font></b>,<br>因为需要 MAC 地址在以太网内进行 <b><font color="#0000ff">两个设备</font></b> 之间的包传输。
<b><font color="#616161">数据包到达服务器,服务器开始层层拆封,获取 HTTP 请求信息</font></b>
服务器将封装好的数据包进行层层拆封,边拆封边获取有用的信息,进行匹对,对应等。
到最后,服务器的 HTTP 进程根据 HTTP 数据,知道这个请求是要访问一个页面,于是就把这个网页封装在 HTTP 响应报文里。
HTTP 响应报文也需要穿上 TCP、IP、MAC 头部,不过这次是源地址是<br>服务器 IP 地址,目的地址是客户端 IP 地址。然后又经过刚刚的过程。
最后客户端接收到数据包后,也开始层层拆封,最后获取到 HTTP 响应报文,交给浏览器去渲染页面。
最后,客户端要离开了,就会向服务器发起<b><font color="#0000ff"> TCP 四次挥手</font></b>,至此双方的连接就断开了。
Linux 系统是如何收发网络包的?(未完)
网络模型
Linux 网络协议栈
Linux 接收网络包的流程
Linux 发送网络包的流程
总结
0 条评论
下一页