TCP/IP 网络模型有哪几层?
为什么我们需要TCP/IP 网络模型?
同一设备上的进程之间通信的方式有很多种,比如管道、消息队列、共享内存、信号等,但是不同设备上的进程之间通信需要网络通信,而且设备也是多种多样的。因此,协商了一套通用网络协议以兼容各种设备。
该网络协议是分层的,每一层都有自己的角色和职责。接下来我们将基于TCP/IP网络模型来介绍各层。
应用层
我们可以直接访问的顶层是应用程序层。我们在电脑、手机上使用的所有应用软件都是在应用层实现的。然后,当两个不同设备上的应用程序需要通信时,它们将应用程序数据传递到下一层,即传输层。
因此,应用层应该只专注于为用户提供应用功能,例如HTTP、FTP、Telnet、DNS和SMTP。
应用层不需要关心数据如何发送。这意味着您只需将包裹交给快递员即可,快递员无需携带。请注意快递方式。
此外,应用层运行在操作系统的用户模式下,传输层及以下层运行在内核模式下。
传输层
应用层数据包被传递到传输层,传输层为应用层提供网络支持。
传输层有两种传输协议:TCP 和UDP。
TCP 的正式名称是传输控制协议。大多数应用程序使用TCP传输层协议,例如HTTP应用层协议。 TCP比UDP有更多的功能,如流量控制、超时重传、拥塞控制等。这一切都是为了保证数据包能够发送给对方。
UDP只发送数据包,不能保证数据包一定能到达另一端,但实时性比较高,传输效率也较高。当然,UDP也可以通过在应用层实现TCP的特性来提供可靠的传输,但是实现一个商业上可靠的UDP传输协议并不容易。
应用程序需要发送的数据可能非常大,如果直接发送则难以控制,因此如果传输层数据包大小超过MSS(TCP最大分段长度),则需要发送数据包。因为它被分成块,即使中间有数据包,如果一个块丢失或损坏,只需要重传这个块,而不是整个数据包。在TCP协议中,每个块称为一个TCP段。
当设备充当接收器时,传输层负责将数据包传递给应用程序。但是,设备上可能有许多接收或发送数据的应用程序,因此必须使用数字来区分应用程序。数字是端口。
例如,端口80 通常由Web 服务器使用,端口22 通常用于远程登录服务器。浏览器(客户端)中的每个选项卡栏都是一个单独的进程,操作系统为这些进程分配临时端口号。
传输层数据包包含端口号,以便接收者可以识别数据包发送到哪个应用程序。
网络层
当您第一次介绍传输层时,您可能会认为传输层负责将数据从一个设备发送到另一个设备,但实际上传输层并不负责。
现实场景中的网络链路是复杂的,沿途有各种电路和分支,必须选择不同的路径和节点将数据从一个设备发送到另一个设备,但传输层的设计理念很简单。要强调效率、重点。如果传输层也负责此功能,则违反了设计原则。
换句话说,我们不希望传输层协议处理太多的事情,只是适当地为应用程序服务,充当应用程序之间数据传输的媒介,帮助实现应用程序间的通信。实际的发送功能保持不变。下一层是互联网层。
最常用的网络层是IP协议(Internet Protocol)。如果IP报文的大小超过MTU,IP协议将传输层报文作为数据部分,并添加IP报头来创建IP报文。以太网)(1500 字节)被重新分段,以将IP 消息发送到网络。
网络层负责将数据从一个设备传输到另一设备。世界上有这么多的设备,它们如何找到彼此呢?因此,网络层需要一个编号来区分设备。
IPv4 协议通常使用IP 地址对设备进行编号。 IP 地址共有32 位,分为四段,每段8 位(例如192.168.100.1)。一个简单的IP地址就足以区分设备,但世界上的设备太多了,必须一一匹配特别繁琐。这显然是不科学的。
因此,IP地址必须分为两种含义:
一是网络号,它标识IP地址属于哪个“子网”。另一个是主机号,它标识同一“子网”内的不同主机。
又是如何划分的呢?它必须与子网掩码结合起来计算IP 地址的网络号和主机号。
例如,10.100.122.0/24,其后面的/24表示子网掩码255.255.255.0,255.255.255.0的二进制数为“11111111-11111111-11111111-00000000”。有多少个1?总共?无需数。使用/24 代替255.255.255.0 以简化子网掩码表达式。
一旦知道子网掩码,如何计算网络地址和主机地址?
将10.100.122.2和255.255.255.0按位与运算,得到网络号,如下所示。
将255.255.255.0取反,与IP地址按位与运算,得到主机号。
要了解子网掩码的作用,您可以搜索子网掩码计算器并自行更改“掩码位”的值。
然后,在寻址过程中,首先匹配相同的网络号(即找到相同的子网),然后找到相应的主机。
除了寻址之外,IP协议还有一个重要的功能:路由。在现实场景中,两个设备不是通过网线连接的,而是通过网关、路由器、交换机等许多网络设备,从而形成许多网络路径。当数据包到达网络时,节点使用路由算法来进行连接。决定接下来要走哪条路。
路由器的寻址任务是找到目标地址所在的子网,并将数据包转发到相应的网络。
因此,IP协议的寻址功能就是告诉下一个目的地该往哪个方向走,而路由则根据“下一个目的地”来选择路径。寻址就像导航,路由就像操作方向盘。
网络接口层
IP 标头生成后,将被传递到网络接口层(链路层),网络接口层将MAC 标头添加到IP 标头之前,将其封装成数据帧,然后通过网络发送。
IP 标头中的接收方IP 地址代表网络数据包的目的地。通过这个地址,你可以决定将数据包发送到哪里,但在以太网世界中,这个想法行不通。
什么是以太网?计算机以太网接口、Wi-Fi接口、以太网交换机、路由器上的千兆和10千兆以太网端口以及网线都是以太网的组成部分。以太网是一种允许附近设备在“局域网”内相互连接和通信的技术。
以太网与IP 的不同之处在于它如何确定网络数据包的目的地。因此在以太网中,MAC 报头就是用于此目的。用于通讯。
MAC头是以太网中使用的头,包含接收方和发送方的MAC地址等信息,可以通过ARP协议检索这些信息。
因此,网络接口层主要负责向网络层提供“链路级”传输服务,通过以太网或WiFi等底层网络传输原始数据包,并运行在网卡级别,它使用MAC。地址来识别设备。在网络设备上。
总结
总而言之,TCP/IP 网络通常分为四层,从上到下:应用层、传输层、网络层和网络接口层。
表示各层的封装格式。
网络接口层的传输单元是帧,IP层的传输单元是数据包,TCP层的传输单元是段,HTTP层的传输单元是消息或消息。然而,这些术语之间没有本质区别,它们可以统称为数据包。
键入网址到网页显示,期间发生了什么?
很多朋友在面试过程中可能会遇到这样的面试问题:“我输入一个URL并在网页上显示后会发生什么?”
不用说,这个问题经常被问到。前几天,当我通过电话面试应聘者时,坐在我旁边的老板也问了我这个问题。
现在让我们使用下图中更简单的网络拓扑模型来检查发生了什么。
孤单小弟 —— HTTP
浏览器执行的第一步是解析URL
浏览器执行的第一步是解析URL 并生成发送到Web 服务器的请求信息。
我们来看看长URL 的每个元素代表什么,如下图所示。
因此,图中的长URL实际上是在请求服务器上的文件资源。
如果省略上图中蓝色的URL 元素,应该请求哪个文件?
如果没有路径名,则不会产生混淆,因为您将访问根目录中预先配置的默认文件,即/index.html 或/default.html 文件。
生成HTTP请求信息
解析URL 后,浏览器确定Web 服务器和文件名,并根据此信息生成HTTP 请求消息。
单独的HTTP 数据包内容如下: “我被送进了这么一个小包裹,没有任何亲人或朋友,谁会知道我的情况?谁会载我一程?你会保护我吗?目的地?” ” 尽管心存疑虑,但我还是义无反顾地开始了我的旅程!
真实地址查询 —— DNS
浏览器解析URL 并生成HTTP 消息后,必须委托操作系统将消息发送到Web 服务器。
不过,在发送之前,还有一项任务:查询服务器域名对应的IP地址。这是因为当您委托向操作系统发送消息时,您必须提供通信对象的IP 地址。
例如,拨打电话时,您需要知道对方的电话号码,但由于电话号码很难记住,因此您通常会在通讯录中注册对方的电话号码+姓名。
因此,有一类专门存储Web服务器的域名与IP对应关系的服务器:DNS服务器。
域名层次结构
DNS 中的域名以句点分隔,例如www.server.com。这里的句点代表不同级别之间的界限。
对于域名来说,越靠右,级别越高。
毕竟域名是外国人发明的,所以他们的思维方式和中国人相反。例如,在谈论城市中的地方时,外国人更喜欢谈论小地方而不是大地方(街、区等)。 (XX市、XX省等),中国更喜欢从大到小顺序说话(XX省、XX市、XX区、XX街道等)。
事实上,域名末尾有一个点(例如,www.server.com)。最后一个点代表根域名。
即根域在顶级,下一级是.com顶级域,再下一级是server.com。
因此,域名的层次关系类似于树形结构。
根DNS服务器(.) 顶级域名DNS服务器(.com) 权威DNS服务器(server.com)
根域的DNS服务器信息存储在Internet上的所有DNS服务器上。
这允许任何DNS 服务器找到并访问您的根域DNS 服务器。
因此,客户端只要能找到DNS服务器,就可以通过它找到根域DNS服务器,并顺着路径找到下层的目标DNS服务器。
域名解析工作流程
客户端首先发送DNS请求,询问www.server.com的IP,并将其发送到本地DNS服务器(即客户端TCP/IP设置中输入的DNS服务器地址)。本地域名服务器收到客户端的请求后,如果在其缓存的表中找到www.server.com,则直接返回IP地址。如果没有,本地DNS就向根域名服务器询问:“老大,能给我www.server.com的IP地址吗?”根域名服务器不直接用于域名。它也可以显示道路,尽管分辨率不同。当根DNS收到本地DNS的请求时,看到后缀是.com,并显示“域名www.server.com由.com区域管理,服务于.com”。您可以询问顶级域名服务器的地址。 “当本地DNS 收到顶级域名服务器的地址时,它会发起请求并询问:‘您能给我www.server.com 的IP 地址吗?’” “顶级域名服务器说,‘我给你负责www.server.com区域的权威DNS服务器的地址,你应该可以查询到。’”然后本地DNS 现在询问权威服务器。 DNS服务器:“第三个子www.server.com对应的IP是什么?”“server.com的权威DNS服务器,这是域名解析结果的原始来源,为什么叫权威?”是我的域名吗?权威DNS服务器查询后告诉本地DNS对应的DNS“IP地址X.X.X.X”是本地DNS返回给客户端的IP地址,目标与客户端之间建立了连接。目标。
至此,DNS解析过程完成。总结一下,我画了一个整个流程的图。
DNS域名解析的过程非常有趣,类似于日常生活中向别人问路的过程。它只提供指示,而不提供线索。
每次解析域名都需要经过太多步骤吗?
当然不是。有一种东西叫缓存。
浏览器首先检查是否有该域名的缓存,如果没有,则检查操作系统是否有。如果没有,我又检查了hosts文件,那里什么也没有,所以我询问“本地DNS服务器”。
数据包读取: “DNS大哥太棒了,我找到了目的地,我还是一头雾水,我想发送,但是接下来我需要谁的帮助呢?”
指南好帮手 —— 协议栈
通过DNS获取IP后,HTTP发送工作就可以交给操作系统的协议栈了。
在内部,协议栈分为几个部分,每个部分负责不同的任务。等级关系有一定的规则:上级将工作委托给下级,下级执行委托的工作。
应用程序(浏览器)调用套接字库来委托协议栈的工作。在协议栈的顶层,有两个部分负责发送和接收数据:TCP和UDP协议,这两个发送协议接受应用层委托来执行数据发送和接收操作。
协议栈的下半部分使用IP协议来控制网络数据包的发送和接收操作。当您通过Internet 上传数据时,数据会被分解为网络数据包块,IP 将网络数据包发送到网络数据包。伙伴。
IP还包括ICMP和ARP协议。
ICMP用于通知网络数据包传输过程中出现的错误和各种控制信息。 ARP用于根据IP地址查询对应的以太网MAC地址。
IP下面的网卡驱动负责控制网卡硬件,最底层的网卡则负责完成实际的发送和接收操作,即在网线内发送和接收信号。
读完这篇指南后,数据包说道: “现在我们知道我们需要这么多优秀人才的帮助,我们将首先在TCP 寻找优秀人才!”
可靠传输 —— TCP
HTTP是基于TCP协议发送的,所以我们先来了解一下TCP协议。
TCP 标头格式
首先,我们看一下TCP数据包头的格式。
首先,源端口号和目标端口号至关重要。如果没有这两个端口号,数据将不知道要发送到哪个应用程序。
接下来是数据包的序列号。这是为了解决数据包乱序问题。
应该还有一个确认号码,但目的是看对方是否收到。如果您没有收到,则需要重新发送,直到收到为止。这是为了解决丢包问题。
接下来,有一些状态位。例如SYN发起连接、ACK响应、RST重连、FIN终止连接等。 TCP是面向连接的,所以双方都必须维护连接的状态。发送这些包含状态位的数据包会更改双方的状态。
另一个重要的事情是窗口大小。 TCP要求每个通信方声明一个窗口(缓存大小)来标识其当前的处理能力。不能传输太快而饿死,也不能传输太慢而饿死。
除了流量控制之外,TCP 还执行拥塞控制。对于交通是否真的拥堵,你无能为力。换句话说,TCP所能做的就是控制发送速率。如果你无法改变世界,那就改变自己。
TCP在发送数据之前,需要进行三次握手来建立连接。
在HTTP 发送数据之前,TCP 必须首先建立连接。建立TCP 连接通常称为三向握手。
所谓的“连接”无非是在建立连接的过程中两台计算机内部维护的一个状态机。两种状态变化的时序图如下。
最初,客户端和服务器都处于CLOSED 状态。首先,服务器主动监听特定端口,并进入LISTEN状态。
然后客户端主动发起SYN连接,并进入SYN-SENT状态。
当服务器收到发起的连接、返回SYN 并确认客户端的SYN 时,就进入SYN-RCVD 状态。
客户端收到服务器发送的SYN和ACK后,发送ACK确认SYN,并由于发送和接收成功而进入ESTABLISHED状态。
服务器收到ACK的ACK后,因为也在发送和接收,所以进入ESTABLISHED状态。
因此,三次握手的目的是保证双方都能发送和接收。
如何查看TCP 连接状态?
要查看TCP 连接状态,可以在Linux 上使用netstat -napt 命令。
TCP分割数据
当HTTP请求报文比较长,超过了MSS的长度时,TCP必须将HTTP数据分块发送,而不是一次性发送所有数据。
MTU:网络数据包的最大长度。对于以太网,通常为1500 字节。 MSS:删除IP 和TCP 标头后,网络数据包中可以容纳的TCP 数据的最大长度。
数据被分为MSS长度单元,每段数据被放入一个单独的网络数据包中。这意味着每条数据都附加了TCP头信息并传递给IP模块来传输数据。
生成TCP 消息
TCP 协议有两个端口:一个是浏览器监听的端口(通常是随机生成的),另一个是Web 服务器监听的端口(HTTP 的默认端口号是80;端口号是80)。 HTTPS 编号为443)。
两方建立连接后,TCP 消息的数据部分包含HTTP 标头和必须组装并传递到底层网络层进行处理的数据。
此时的网络数据包消息如下所示:
这时,我遇到了一个TCP数据包,兴奋地说: “太好了!我遇到了可靠的TCP传输,给我加了一个TCP头,我不再孤单了,我很安全,我有一个大老板。”“保护我的可靠出生!但我该去哪里?”去?”
远程定位 —— IP
TCP模块在执行连接、发送、接收、断开等各个阶段的操作时,必须委托IP模块将数据封装成网络数据包发送给通信对象。
IP 标头格式
首先,让我们看一下IP数据包报头的格式。
IP协议有源地址IP和目的地址IP。
源地址IP是客户端输出的IP地址,目的地址是通过DNS域名解析得到的Web服务器IP。
由于HTTP 是通过TCP 发送的,因此IP 标头中的协议号必须输入06(十六进制)以指示该协议是TCP。
假设客户端有多个网卡,那么它将有多个IP地址。我应该选择哪个IP作为IP标头的源地址?
如果您有多个网卡,则在输入源地址IP时必须决定输入哪个地址。该确定对应于确定应该使用哪个网卡来在多个网卡之间传输分组。
此时需要根据路由表中的规则判断源地址IP是哪个网卡。
在Linux操作系统上,可以使用route -n命令来显示当前系统路由表。
例如,根据上面的路由表,假设您的Web 服务器的目标地址是192.168.10.200。
首先,与第一个条目的子网掩码(Genmask)执行AND运算。结果是192.168.10.0,但第一个条目的目标是192.168.3.0。比赛失败是因为两人不一致。然后与第二个条目的子网掩码执行AND 运算,结果为192.168.10.0,它与第二个条目的目的地192.168.10.0 匹配,因此将使用eth1 网卡的IP 地址。 IP 标头地址。
因此,假设Web服务器的目标地址是10.100.20.100,则将根据上面路由表中的规则进行确定,结果将与第三条条目匹配。
第三个条目比较特殊,目标地址和子网掩码都是0.0.0.0,如果所有其他条目都不匹配,则该行会自动匹配。然后数据包被发送到路由器的IP 地址。
IP消息的生成
此时的网络数据包消息如下所示:
此时添加了IP头的数据包读取为: “IP 老板给我指明了方向,它给我添加了IP 标头,现在我可以远程定位,但我的目的地很远,那么我下一步该去哪里呢?
两点传输 —— MAC
IP 标头生成后,网络数据包必须在IP 标头之前添加MAC 标头。
MAC头格式
MAC报头是以太网中使用的报头,其中包含接收方和发送方的MAC地址等信息。
对于点对点传输,MAC 标头中需要发送方MAC 地址和接收方目标MAC 地址。
通常,TCP/IP 通信仅使用MAC 标头中的协议类型。
0800:IP协议0806:ARP协议
如何查看发送者和接收者的MAC地址?
获取发送方的MAC地址比较简单;MAC地址是在网卡制造时写入ROM中的。只需读取该值并将其写入MAC 标头即可。
接收者的MAC地址稍微复杂一些。只要你告诉以太网对方的MAC地址,以太网就可以帮助把数据包发送到那里。所以,这里当然需要输入对方的MAC地址。
因此,您必须首先决定将数据包发送给谁。您只需检查路由表即可得知这一点。只需在路由表中找到匹配的条目,然后将数据包发送到网关列中的IP 地址即可。
既然您知道将其发送到哪里,那么如何获取其MAC 地址呢?
不知道对方的MAC地址?如果你不明白,就尖叫。
目前,需要通过ARP协议来查找路由器的MAC地址。
ARP协议通过以太网进行广播,并向以太网上的所有设备喊话:“谁拥有这个IP地址?请告诉我你的MAC地址。”
然后有人回复:“这个IP地址是我的,我的MAC地址是XXXX。”
如果对方与您在同一子网,您可以通过上述步骤获取对方的MAC地址。然后将该MAC 地址写入MAC 标头以完成MAC 标头。
每次都要直播不是很痛苦吗?
请不要担心。将来,操作系统会将查询结果存储在一个称为ARP缓存的内存区域中以供将来使用,但缓存时间将只有几分钟。
换句话说,在签订合同时:
首先,查询ARP缓存。如果存储了对端的MAC地址,则无需发送ARP查询,可以直接使用ARP缓存中的地址。如果对等方的MAC 地址不在ARP 缓存中,则发送ARP 广播查询。
显示ARP缓存的内容
在Linux 部门
统中,我们可以使用 arp -a 命令来查看 ARP 缓存的内容。
MAC 报文生成
至此,网络包的报文如下图。
此时,加上了 MAC 头部的数据包万分感谢,说道 :“感谢 MAC 大佬,我知道我下一步要去哪了!我现在有很多头部兄弟,相信我可以到达最终的目的地!”。 带着众多头部兄弟的数据包,终于准备要出门了。
出口 —— 网卡
网络包只是存放在内存中的一串二进制数字信息,没有办法直接发送给对方。因此,我们需要将数字信息转换为电信号,才能在网线上传输,也就是说,这才是真正的数据发送过程。
负责执行这一操作的是网卡,要控制网卡还需要靠网卡驱动程序。
网卡驱动获取网络包之后,会将其复制到网卡内的缓存区中,接着会在其开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列。
起始帧分界符是一个用来表示包起始位置的标记末尾的 FCS(帧校验序列)用来检查包传输过程是否有损坏
最后网卡会将包转为电信号,通过网线发送出去。
唉,真是不容易,发一个包,真是历经千辛万苦。致此,一个带有许多头部的数据终于踏上寻找目的地的征途了!
送别者 —— 交换机
下面来看一下包是如何通过交换机的。交换机的设计是将网络包原样转发到目的地。交换机工作在 MAC 层,也称为二层网络设备。
交换机的包接收操作
首先,电信号到达网线接口,交换机里的模块进行接收,接下来交换机里的模块将电信号转换为数字信号。
然后通过包末尾的 FCS 校验错误,如果没问题则放到缓冲区。这部分操作基本和计算机的网卡相同,但交换机的工作方式和网卡不同。
计算机的网卡本身具有 MAC 地址,并通过核对收到的包的接收方 MAC 地址判断是不是发给自己的,如果不是发给自己的则丢弃;相对地,交换机的端口不核对接收方 MAC 地址,而是直接接收所有的包并存放到缓冲区中。因此,和网卡不同,交换机的端口不具有 MAC 地址。
将包存入缓冲区后,接下来需要查询一下这个包的接收方 MAC 地址是否已经在 MAC 地址表中有记录了。
交换机的 MAC 地址表主要包含两个信息:
一个是设备的 MAC 地址,另一个是该设备连接在交换机的哪个端口上。
举个例子,如果收到的包的接收方 MAC 地址为 00-02-B3-1C-9C-F9,则与图中表中的第 3 行匹配,根据端口列的信息,可知这个地址位于 3 号端口上,然后就可以通过交换电路将包发送到相应的端口了。
所以,交换机根据 MAC 地址表查找 MAC 地址,然后将信号发送到相应的端口。
当 MAC 地址表找不到指定的 MAC 地址会怎么样?
地址表中找不到指定的 MAC 地址。这可能是因为具有该地址的设备还没有向交换机发送过包,或者这个设备一段时间没有工作导致地址被从地址表中删除了。
这种情况下,交换机无法判断应该把包转发到哪个端口,只能将包转发到除了源端口之外的所有端口上,无论该设备连接在哪个端口上都能收到这个包。
这样做不会产生什么问题,因为以太网的设计本来就是将包发送到整个网络的,然后只有相应的接收者才接收包,而其他设备则会忽略这个包。
有人会说:“这样做会发送多余的包,会不会造成网络拥塞呢?”
其实完全不用过于担心,因为发送了包之后目标设备会作出响应,只要返回了响应包,交换机就可以将它的地址写入 MAC 地址表,下次也就不需要把包发到所有端口了。
局域网中每秒可以传输上千个包,多出一两个包并无大碍。
此外,如果接收方 MAC 地址是一个广播地址,那么交换机会将包发送到除源端口之外的所有端口。
以下两个属于广播地址:
MAC 地址中的 FF:FF:FF:FF:FF:FFIP 地址中的 255.255.255.255
数据包通过交换机转发抵达了路由器,准备要离开土生土长的子网了。此时,数据包和交换机离别时说道:“感谢交换机兄弟,帮我转发到出境的大门,我要出远门啦!”
出境大门 —— 路由器
路由器与交换机的区别
网络包经过交换机之后,现在到达了路由器,并在此被转发到下一个路由器或目标设备。
这一步转发的工作原理和交换机类似,也是通过查表判断包转发的目标。
不过在具体的操作过程上,路由器和交换机是有区别的。
因为路由器是基于 IP 设计的,俗称三层网络设备,路由器的各个端口都具有 MAC 地址和 IP 地址;而交换机是基于以太网设计的,俗称二层网络设备,交换机的端口不具有 MAC 地址。
路由器基本原理
路由器的端口具有 MAC 地址,因此它就能够成为以太网的发送方和接收方;同时还具有 IP 地址,从这个意义上来说,它和计算机的网卡是一样的。
当转发包时,首先路由器端口会接收发给自己的以太网包,然后路由表查询转发目标,再由相应的端口作为发送方将以太网包发送出去。
路由器的包接收操作
首先,电信号到达网线接口部分,路由器中的模块会将电信号转成数字信号,然后通过包末尾的 FCS 进行错误校验。
如果没问题则检查 MAC 头部中的接收方 MAC 地址,看看是不是发给自己的包,如果是就放到接收缓冲区中,否则就丢弃这个包。
总的来说,路由器的端口都具有 MAC 地址,只接收与自身地址匹配的包,遇到不匹配的包则直接丢弃。
查询路由表确定输出端口
完成包接收操作之后,路由器就会去掉包开头的 MAC 头部。
MAC 头部的作用就是将包送达路由器,其中的接收方 MAC 地址就是路由器端口的 MAC 地址。因此,当包到达路由器之后,MAC 头部的任务就完成了,于是 MAC 头部就会被丢弃。
接下来,路由器会根据 MAC 头部后方的 IP 头部中的内容进行包的转发操作。
转发操作分为几个阶段,首先是查询路由表判断转发目标。
具体的工作流程根据上图,举个例子。
假设地址为 10.10.1.101 的计算机要向地址为 192.168.1.100 的服务器发送一个包,这个包先到达图中的路由器。
判断转发目标的第一步,就是根据包的接收方 IP 地址查询路由表中的目标地址栏,以找到相匹配的记录。
路由匹配和前面讲的一样,每个条目的子网掩码和 192.168.1.100 IP 做 & 与运算后,得到的结果与对应条目的目标地址进行匹配,如果匹配就会作为候选转发目标,如果不匹配就继续与下个条目进行路由匹配。
如第二条目的子网掩码 255.255.255.0 与 192.168.1.100 IP 做 & 与运算后,得到结果是 192.168.1.0 ,这与第二条目的目标地址 192.168.1.0 匹配,该第二条目记录就会被作为转发目标。
实在找不到匹配路由时,就会选择默认路由,路由表中子网掩码为 0.0.0.0 的记录表示「默认路由」。
路由器的发送操作
接下来就会进入包的发送操作。
首先,我们需要根据路由表的网关列判断对方的地址。
如果网关是一个 IP 地址,则这个IP 地址就是我们要转发到的目标地址,还未抵达终点,还需继续需要路由器转发。如果网关为空,则 IP 头部中的接收方 IP 地址就是要转发到的目标地址,也是就终于找到 IP 包头里的目标地址了,说明已抵达终点。
知道对方的 IP 地址之后,接下来需要通过 ARP 协议根据 IP 地址查询 MAC 地址,并将查询的结果作为接收方 MAC 地址。
路由器也有 ARP 缓存,因此首先会在 ARP 缓存中查询,如果找不到则发送 ARP 查询请求。
接下来是发送方 MAC 地址字段,这里填写输出端口的 MAC 地址。还有一个以太类型字段,填写 0800 (十六进制)表示 IP 协议。
网络包完成后,接下来会将其转换成电信号并通过端口发送出去。这一步的工作过程和计算机也是相同的。
发送出去的网络包会通过交换机到达下一个路由器。由于接收方 MAC 地址就是下一个路由器的地址,所以交换机会根据这一地址将包传输到下一个路由器。
接下来,下一个路由器会将包转发给再下一个路由器,经过层层转发之后,网络包就到达了最终的目的地。
不知你发现了没有,在网络包传输的过程中,源 IP 和目标 IP 始终是不会变的,一直变化的是 MAC 地址,因为需要 MAC 地址在以太网内进行两个设备之间的包传输。
数据包通过多个路由器道友的帮助,在网络世界途经了很多路程,最终抵达了目的地的城门!城门值守的路由器,发现了这个小兄弟数据包原来是找城内的人,于是它就将数据包送进了城内,再经由城内的交换机帮助下,最终转发到了目的地了。数据包感慨万千的说道:“多谢这一路上,各路大侠的相助!”
互相扒皮 —— 服务器 与 客户端
数据包抵达了服务器,服务器肯定高兴呀,正所谓有朋自远方来,不亦乐乎?
服务器高兴的不得了,于是开始扒数据包的皮!就好像你收到快递,能不兴奋吗?
数据包抵达服务器后,服务器会先扒开数据包的 MAC 头部,查看是否和服务器自己的 MAC 地址符合,符合就将包收起来。
接着继续扒开数据包的 IP 头,发现 IP 地址符合,根据 IP 头中协议项,知道自己上层是 TCP 协议。
于是,扒开 TCP 的头,里面有序列号,需要看一看这个序列包是不是我想要的,如果是就放入缓存中然后返回一个 ACK,如果不是就丢弃。TCP头部里面还有端口号, HTTP 的服务器正在监听这个端口号。
于是,服务器自然就知道是 HTTP 进程想要这个包,于是就将包发给 HTTP 进程。
服务器的 HTTP 进程看到,原来这个请求是要访问一个页面,于是就把这个网页封装在 HTTP 响应报文里。
HTTP 响应报文也需要穿上 TCP、IP、MAC 头部,不过这次是源地址是服务器 IP 地址,目的地址是客户端 IP 地址。
穿好头部衣服后,从网卡出去,交由交换机转发到出城的路由器,路由器就把响应数据包发到了下一个路由器,就这样跳啊跳。
最后跳到了客户端的城门把守的路由器,路由器扒开 IP 头部发现是要找城内的人,于是又把包发给了城内的交换机,再由交换机转发到客户端。
客户端收到了服务器的响应数据包后,同样也非常的高兴,客户能拆快递了!
于是,客户端开始扒皮,把收到的数据包的皮扒剩 HTTP 响应报文后,交给浏览器去渲染页面,一份特别的数据包快递,就这样显示出来了!
最后,客户端要离开了,向服务器发起了 TCP 四次挥手,至此双方的连接就断开了。
一个数据包臭不要脸的感受
下面内容的 「我」,代表「臭美的数据包角色」。注:(括号的内容)代表我的吐槽,三连呸!
我一开始我虽然孤单、不知所措,但没有停滞不前。我依然满怀信心和勇气开始了征途。(你当然有勇气,你是应用层数据,后面有底层兄弟当靠山,我呸!)
我很庆幸遇到了各路神通广大的大佬,有可靠传输的 TCP、有远程定位功能的 IP、有指明下一站位置的 MAC 等(你当然会遇到,因为都被计算机安排好的,我呸!)。
这些大佬都给我前面加上了头部,使得我能在交换机和路由器的转发下,抵达到了目的地!(哎,你也不容易,不吐槽了,放过你!)
这一路上的经历,让我认识到了网络世界中各路大侠协作的重要性,是他们维护了网络世界的秩序,感谢他们!(我呸,你应该感谢众多计算机科学家!)
参考资料
[1] 户根勤.网络是怎么连接的.人民邮电出版社.
[2] 刘超.趣谈网络协议.极客时间.
Linux 系统是如何收发网络包的?
这次,就围绕一个问题来说。
Linux 系统是如何收发网络包的?
网络模型
为了使得多种设备能通过网络相互通信,和为了解决各种不同设备在网络互联中的兼容性问题,国际标准化组织制定了开放式系统互联通信参考模型(Open System Interconnection Reference Model),也就是 OSI 网络模型,该模型主要有 7 层,分别是应用层、表示层、会话层、传输层、网络层、数据链路层以及物理层。
每一层负责的职能都不同,如下:
应用层,负责给应用程序提供统一的接口;表示层,负责把数据转换成兼容另一个系统能识别的格式;会话层,负责建立、管理和终止表示层实体之间的通信会话;传输层,负责端到端的数据传输;网络层,负责数据的路由、转发、分片;数据链路层,负责数据的封帧和差错检测,以及 MAC 寻址;物理层,负责在物理网络中传输数据帧;
由于 OSI 模型实在太复杂,提出的也只是概念理论上的分层,并没有提供具体的实现方案。
事实上,我们比较常见,也比较实用的是四层模型,即 TCP/IP 网络模型,Linux 系统正是按照这套网络模型来实现网络协议栈的。
TCP/IP 网络模型共有 4 层,分别是应用层、传输层、网络层和网络接口层,每一层负责的职能如下:
应用层,负责向用户提供一组应用程序,比如 HTTP、DNS、FTP 等;传输层,负责端到端的通信,比如 TCP、UDP 等;网络层,负责网络包的封装、分片、路由、转发,比如 IP、ICMP 等;网络接口层,负责网络包在物理网络中的传输,比如网络包的封帧、 MAC 寻址、差错检测,以及通过网卡传输网络帧等;
TCP/IP 网络模型相比 OSI 网络模型简化了不少,也更加易记,它们之间的关系如下图:
不过,我们常说的七层和四层负载均衡,是用 OSI 网络模型来描述的,七层对应的是应用层,四层对应的是传输层。
Linux 网络协议栈
我们可以把自己的身体比作应用层中的数据,打底衣服比作传输层中的 TCP 头,外套比作网络层中 IP 头,帽子和鞋子分别比作网络接口层的帧头和帧尾。
在冬天这个季节,当我们要从家里出去玩的时候,自然要先穿个打底衣服,再套上保暖外套,最后穿上帽子和鞋子才出门,这个过程就好像我们把 TCP 协议通信的网络包发出去的时候,会把应用层的数据按照网络协议栈层层封装和处理。
你从下面这张图可以看到,应用层数据在每一层的封装格式。
其中:
传输层,给应用数据前面增加了 TCP 头;网络层,给 TCP 数据包前面增加了 IP 头;网络接口层,给 IP 数据包前后分别增加了帧头和帧尾;
这些新增的头部和尾部,都有各自的作用,也都是按照特定的协议格式填充,这每一层都增加了各自的协议头,那自然网络包的大小就增大了,但物理链路并不能传输任意大小的数据包,所以在以太网中,规定了最大传输单元(MTU)是 1500 字节,也就是规定了单次传输的最大 IP 包大小。
当网络包超过 MTU 的大小,就会在网络层分片,以确保分片后的 IP 包不会超过 MTU 大小,如果 MTU 越小,需要的分包就越多,那么网络吞吐能力就越差,相反的,如果 MTU 越大,需要的分包就越少,那么网络吞吐能力就越好。
知道了 TCP/IP 网络模型,以及网络包的封装原理后,那么 Linux 网络协议栈的样子,你想必猜到了大概,它其实就类似于 TCP/IP 的四层结构:
从上图的的网络协议栈,你可以看到:
应用程序需要通过系统调用,来跟 Socket 层进行数据交互;Socket 层的下面就是传输层、网络层和网络接口层;最下面的一层,则是网卡驱动程序和硬件网卡设备;
Linux 接收网络包的流程
网卡是计算机里的一个硬件,专门负责接收和发送网络包,当网卡接收到一个网络包后,会通过 DMA 技术,将网络包写入到指定的内存地址,也就是写入到 Ring Buffer ,这个是一个环形缓冲区,接着就会告诉操作系统这个网络包已经到达。
那应该怎么告诉操作系统这个网络包已经到达了呢?
最简单的一种方式就是触发中断,也就是每当网卡收到一个网络包,就触发一个中断告诉操作系统。
但是,这存在一个问题,在高性能网络场景下,网络包的数量会非常多,那么就会触发非常多的中断,要知道当 CPU 收到了中断,就会停下手里的事情,而去处理这些网络包,处理完毕后,才会回去继续其他事情,那么频繁地触发中断,则会导致 CPU 一直没完没了的处理中断,而导致其他任务可能无法继续前进,从而影响系统的整体效率。
所以为了解决频繁中断带来的性能开销,Linux 内核在 2.6 版本中引入了 NAPI 机制,它是混合「中断和轮询」的方式来接收网络包,它的核心概念就是不采用中断的方式读取数据,而是首先采用中断唤醒数据接收的服务程序,然后 poll 的方法来轮询数据。
因此,当有网络包到达时,会通过 DMA 技术,将网络包写入到指定的内存地址,接着网卡向 CPU 发起硬件中断,当 CPU 收到硬件中断请求后,根据中断表,调用已经注册的中断处理函数。
硬件中断处理函数会做如下的事情:
需要先「暂时屏蔽中断」,表示已经知道内存中有数据了,告诉网卡下次再收到数据包直接写内存就可以了,不要再通知 CPU 了,这样可以提高效率,避免 CPU 不停的被中断。接着,发起「软中断」,然后恢复刚才屏蔽的中断。
至此,硬件中断处理函数的工作就已经完成。
硬件中断处理函数做的事情很少,主要耗时的工作都交给软中断处理函数了。
软中断的处理
内核中的 ksoftirqd 线程专门负责软中断的处理,当 ksoftirqd 内核线程收到软中断后,就会来轮询处理数据。
ksoftirqd 线程会从 Ring Buffer 中获取一个数据帧,用 sk_buff 表示,从而可以作为一个网络包交给网络协议栈进行逐层处理。
网络协议栈
首先,会先进入到网络接口层,在这一层会检查报文的合法性,如果不合法则丢弃,合法则会找出该网络包的上层协议的类型,比如是 IPv4,还是 IPv6,接着再去掉帧头和帧尾,然后交给网络层。
到了网络层,则取出 IP 包,判断网络包下一步的走向,比如是交给上层处理还是转发出去。当确认这个网络包要发送给本机后,就会从 IP 头里看看上一层协议的类型是 TCP 还是 UDP,接着去掉 IP 头,然后交给传输层。
传输层取出 TCP 头或 UDP 头,根据四元组「源 IP、源端口、目的 IP、目的端口」 作为标识,找出对应的 Socket,并把数据放到 Socket 的接收缓冲区。
最后,应用层程序调用 Socket 接口,将内核的 Socket 接收缓冲区的数据「拷贝」到应用层的缓冲区,然后唤醒用户进程。
至此,一个网络包的接收过程就已经结束了,你也可以从下图左边部分看到网络包接收的流程,右边部分刚好反过来,它是网络包发送的流程。
Linux 发送网络包的流程
如上图的右半部分,发送网络包的流程正好和接收流程相反。
首先,应用程序会调用 Socket 发送数据包的接口,由于这个是系统调用,所以会从用户态陷入到内核态中的 Socket 层,内核会申请一个内核态的 sk_buff 内存,将用户待发送的数据拷贝到 sk_buff 内存,并将其加入到发送缓冲区。
接下来,网络协议栈从 Socket 发送缓冲区中取出 sk_buff,并按照 TCP/IP 协议栈从上到下逐层处理。
如果使用的是 TCP 传输协议发送数据,那么先拷贝一个新的 sk_buff 副本 ,这是因为 sk_buff 后续在调用网络层,最后到达网卡发送完成的时候,这个 sk_buff 会被释放掉。而 TCP 协议是支持丢失重传的,在收到对方的 ACK 之前,这个 sk_buff 不能被删除。所以内核的做法就是每次调用网卡发送的时候,实际上传递出去的是 sk_buff 的一个拷贝,等收到 ACK 再真正删除。
接着,对 sk_buff 填充 TCP 头。这里提一下,sk_buff 可以表示各个层的数据包,在应用层数据包叫 data,在 TCP 层我们称为 segment,在 IP 层我们叫 packet,在数据链路层称为 frame。
你可能会好奇,为什么全部数据包只用一个结构体来描述呢?协议栈采用的是分层结构,上层向下层传递数据时需要增加包头,下层向上层数据时又需要去掉包头,如果每一层都用一个结构体,那在层之间传递数据的时候,就要发生多次拷贝,这将大大降低 CPU 效率。
于是,为了在层级之间传递数据时,不发生拷贝,只用 sk_buff 一个结构体来描述所有的网络包,那它是如何做到的呢?是通过调整 sk_buff 中 data 的指针,比如:
当接收报文时,从网卡驱动开始,通过协议栈层层往上传送数据报,通过增加 skb->data 的值,来逐步剥离协议首部。当要发送报文时,创建 sk_buff 结构体,数据缓存区的头部预留足够的空间,用来填充各层首部,在经过各下层协议时,通过减少 skb->data 的值来增加协议首部。
你可以从下面这张图看到,当发送报文时,data 指针的移动过程。
至此,传输层的工作也就都完成了。
然后交给网络层,在网络层里会做这些工作:选取路由(确认下一跳的 IP)、填充 IP 头、netfilter 过滤、对超过 MTU 大小的数据包进行分片。处理完这些工作后会交给网络接口层处理。
网络接口层会通过 ARP 协议获得下一跳的 MAC 地址,然后对 sk_buff 填充帧头和帧尾,接着将 sk_buff 放到网卡的发送队列中。
这一些工作准备好后,会触发「软中断」告诉网卡驱动程序,这里有新的网络包需要发送,驱动程序会从发送队列中读取 sk_buff,将这个 sk_buff 挂到 RingBuffer 中,接着将 sk_buff 数据映射到网卡可访问的内存 DMA 区域,最后触发真实的发送。
当数据发送完成以后,其实工作并没有结束,因为内存还没有清理。当发送完成的时候,网卡设备会触发一个硬中断来释放内存,主要是释放 sk_buff 内存和清理 RingBuffer 内存。
最后,当收到这个 TCP 报文的 ACK 应答时,传输层就会释放原始的 sk_buff 。
发送网络数据的时候,涉及几次内存拷贝操作?
第一次,调用发送数据的系统调用的时候,内核会申请一个内核态的 sk_buff 内存,将用户待发送的数据拷贝到 sk_buff 内存,并将其加入到发送缓冲区。
第二次,在使用 TCP 传输协议的情况下,从传输层进入网络层的时候,每一个 sk_buff 都会被克隆一个新的副本出来。副本 sk_buff 会被送往网络层,等它发送完的时候就会释放掉,然后原始的 sk_buff 还保留在传输层,目的是为了实现 TCP 的可靠传输,等收到这个数据包的 ACK 时,才会释放原始的 sk_buff 。
第三次,当 IP 层发现 sk_buff 大于 MTU 时才需要进行。会再申请额外的 sk_buff,并将原来的 sk_buff 拷贝为多个小的 sk_buff。
总结
电脑与电脑之间通常都是通过网卡、交换机、路由器等网络设备连接到一起,那由于网络设备的异构性,国际标准化组织定义了一个七层的 OSI 网络模型,但是这个模型由于比较复杂,实际应用中并没有采用,而是采用了更为简化的 TCP/IP 模型,Linux 网络协议栈就是按照了该模型来实现的。
TCP/IP 模型主要分为应用层、传输层、网络层、网络接口层四层,每一层负责的职责都不同,这也是 Linux 网络协议栈主要构成部分。
当应用程序通过 Socket 接口发送数据包,数据包会被网络协议栈从上到下进行逐层处理后,才会被送到网卡队列中,随后由网卡将网络包发送出去。
而在接收网络包时,同样也要先经过网络协议栈从下到上的逐层处理,最后才会被送到应用程序。
#以上关于计算机网络面试基础知识基础篇的相关内容来源网络仅供参考,相关信息请以官方公告为准!
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/91968.html