三、网络协议栈
通常在手机或者电脑上使用的APP,如抖音、快手、淘宝等,这些APP都是在应用层的。用户在应用层的各种请求最终会下达给操作系统,操作系统内除了进程管理、文件管理、内存管理、驱动管理之外,还有一个内嵌的软件协议栈,协议栈将用户的数据进行各种封包后,通过网卡将数据传递到网络当中,数据在网络内部经过各种路由转发,最终将数据传送到了目标服务器
目标服务器本身也是一台计算机,假设该计算机的操作系统就是Linux,而访问目标服务器时使用的可能是Windows、安卓或者IOS等操作系统。此外,对端服务器也有自己的协议栈,对端服务器将拿到数据通过协议栈进行各种解包操作后上交给应用层,在对端服务器的应用层就有一个对应的软件服务器,如抖音服务器、快手服务器、淘宝服务器等,软件服务器内部对收到的用户请求进行各种分析处理后,再将对应的数据以相同的方式返回给用户
不同操作系统的进程管理、文件管理、内存管理、驱动管理的实现方式可能是不一样的。如Windows和Linux实现多线程的方式就是不一样的,Linux中的线程是用轻量级进程模拟的,而Windows中是有真正意义上的线程的
而协议栈是网络标准组织定义的,是具有全球性质的,所有的操作系统都必须支持。虽然客户端和服务端可能使用的是不同种类的操作系统,但每个操作系统实现网络协议栈的方法包括各种细节都是一样的,因此双方对数据进行的封包和解包操作基本一致
网络协议栈
操作系统与网络协议栈有着密切的关系。网络协议栈主要负责数据的通信,其自顶向下可分为四层,分别是应用层、传输层、网络层、数据链路层
网络协议栈各层所处位置:
应用层是位于用户层的。 这部分代码是由网络协议的开发人员来编写的,如HTTP协议、HTTPS协议以及SSH协议等
传输层和网络层是位于操作系统层的。 其中传输层最经典的协议叫做TCP协议,网络层最经典的协议叫做IP协议,这就是我们平常所说的TCP/IP协议
数据链路层是位于驱动层的。 其负责真正的数据传输
有些地方可能将网络协议栈分为了五层,多了最底层的物理层,物理层主要就是利用传输介质为数据链路层提供物理连接,实现比特流的透明传输,是与硬件强相关的
有的书还会将数据链路层和物理层统称为网络接口层,也有书会将网络层称为网际层
网络协议栈各层功能
数据链路层和物理层
要实现通信首先要能够将数据发送出去,而数据链路层和物理层就是负责数据真正的发送过程的
网络层
在数据链路层和物理层的支持下,现在能够将数据发送出去了,但是还应该知道数据应该往哪里发,而网络层完成的就是数据转发,解决了数据去哪里的问题
传输层
有了发送数据的能力,也知道数据应该往哪里发,但是并不能保证发出去的数据能够成功的到达对端主机,比如在传输过程中可能会出现丢包或对端主机关机,甚至对端服务器出错,导致数据传送出现问题。而传输层的工作就是处理传输时遇到的问题,主要是保证数据可靠性
应用层
即网络协议栈的下三层能够保证把数据交付给对端主机,但现在还需要明确的是,将数据发送给对端主机的目的是什么,而这就是应用层要解决的问题。应用层需要根据特定的通信目的,对数据进行分析与处理,以达到某种业务性的目的
网络协议栈的下三层主要的完成的工作就是处理通信细节,而应用层主要完成的就是某种具体的业务细节
四、数据包封装与分用
不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在网络层叫做数据报 (datagram),在链路层叫做帧(frame)
应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(header),称为封装(Encapsulation)
首部信息中包含了一些类似于首部有多长,载荷(payload)有多长,上层协议是什么等信息.
数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,根据首部中的 "上层协议字段" 将数据交给对应的上层协议处理
数据封装的过程:
数据分用的过程:
报头
报头本质也是一种数据,报头一般是通过位段实现的,因此协议栈的每一层都有一个对应的位段来表示当前层的报头
数据封装,实际就是不断给数据加上各种对应的报头,这些报头里面填充的就是对应的各种协议细节
数据解包,实际就是不断从数据中提取对应的报头,并对提取出来的报头进行数据分析
有效载荷
当对端主机收到数据后,需要自底向上贯穿协议栈,依次进行数据的解包与分用。在这个解包的过程中,每一层的协议只需要提取出数据中对应的报头,然后对该报头进行分析处理,而剩下的数据则直接交付给上层即可
因为每一层的协议只关心数据中与当前层对应的报头信息,而剩下信息的具体内容根本不必关心,数据中除当前层的报头以外的数据就被称为"有效载荷"
上层协议在数据封装时添加的报头信息,在下层协议进行数据解包时看来就是有效载荷。比如数据封装时应用层添加的报头信息,在对端主机进行数据解包时,在对端主机的传输层、网络层以及链路层看来,该应用层曾经添加的报头信息就是有效载荷
如何将报头与有效载荷进行分离?
协议栈的每一层都要从数据中提取对应的报头信息,而要将数据中的报头提取出来,首先就需要明确报头与有效载荷之间的界限,这样才能进行分离。而每一层添加报头时都是将报头添加到数据的首部的,因此只要知道了报头的大小,就能够讲报头和有效载荷进行分离
获取报头大小的方法通常有两种:
定长报头。报头的大小是固定的
自描述字段。报头当中提供了一个字段,用来表示报头的长度
每个协议都要提供一种方法获取到报头的大小,这样才能在解包时将报头与有效载荷进行分离
当前层如何知道应该将有效载荷交付给上层的哪个协议?
网络协议栈的每一层都可能会对应多种协议,即便将报头与有效载荷分离了,那当前层应该将有效载荷交付给上层对应的哪个协议呢?实际在每种协议的报头当中,几乎都会包含一个字段,表明我们应该把分离出来的有效载荷交付给上层的哪个协议,这就是分用的过程
协议共性
提供一个将报头与有效载荷分离的方法。
协议当中必须包含一个字段,表明应该将有效载荷交付给上层的哪个协议。
在解包时必须将报头与有效载荷分离,在分用时必须知道应该将有效载荷交付给上层的哪个协议
五、网络传输基本流程
5.1 同局域网的两台主机通信
同一个局域网内的主机是能够直接进行通信的,因为最初局域网设计的目的,就是为了让局域网内的主机能够进行通信
当用户要将文件传输给另一台主机前,该文件数据需要先通过网络协议栈进行封装:
文件数据先交给应用层,应用层添加上对应应用层协议的报头信息后,将数据再交给传输层
传输层收到数据后,再添加上对应传输层协议的报头信息,并将数据继续向下进行交付
网络层收到数据后,再添加上对应网络层协议的报头信息,接着将数据再交给链路层
链路层收到数据后,最后再添加上对应链路层协议的报头信息,至此数据封装完毕
数据封装完毕后就可以通过局域网将其发送给对端主机了,而当对端主机收到数据后,对应也需要通过网络协议栈对该数据进行解包与分用:
链路层收到数据后,先将数据中对应链路层协议的报头信息提取出来,然后将剩下的数据交给网络层
网络层收到该数据后,再将数据中对应网络层协议的报头信息提取出来,然后将剩下的数据继续向上进行交付
传输层收到该数据后,再将数据中对应传输层协议的报头信息提取出来,然后将剩下的数据再交付给应用层
应用层收到数据后,最后将数据中对应应用层协议的报头信息提取出来,至此便完成了数据的解包与分用
任何一台主机在发送数据之前,该数据都要先自顶向下贯穿协议栈来完成数据的封装,在这个过程中,每一层协议都会添加上对应的报头信息;而任何一台主机收到数据后,都要先自底向上贯穿协议栈来完成数据的解包和分用,在这个过程中,每一层协议都会将对应的报头信息提取出来
局域网内传输数据时,该局域网内的所有主机都能收到
在一个局域网当中,除了当前正在进行通信的A主机和B主机以外,还有其他的主机
实际当主机A想要发数据给主机B的时候,该局域网内的其他主机也都收到了该数据,只不过除了主机B以外,其他主机识别到该数据并不是发给自己的,此时其他主机就把收到的数据丢弃了
即在局域网(以太网)通信时,该局域网内所有的主机在底层其实都收到了所有数据,只不过经过筛选后只提交上来了发给自己的数据
碰撞
主机A在向主机B发送数据时,其他主机彼此之间可能也正在进行通信,甚至主机A在和主机B通信的同时也在和其他主机进行通信
但同一局域网中的所有主机在通信时,使用的都是一个共同的通信信道,因此若局域网内的多台主机同时进行通信,此时这些数据之间就可能会相互干扰
每一个局域网都可以看作是一个碰撞域,若某个主机发送出去的数据与其他主机发送的数据之间产生了干扰,我就称这两台主机在该碰撞域中发生了碰撞
如何判断发送出去的数据是否发生了碰撞?
因为发送到局域网当中的数据是所有主机都能够收到的,因此当一个主机将数据发送出去后,该主机本身也是能够收到这个数据的。当该主机收到该数据后就可以将其与之前发送出去的数据进行对比,若发现收到的数据与之前发送出去的数据不相同,则说明在发送过程中发生了碰撞
发生碰撞后如何处理?
当一个主机发现自己发送出去的数据产生了碰撞,此时该主机就要执行"碰撞避免"算法。"碰撞避免"算法实际很简单:当一个主机发送出去的数据产生了碰撞,那么该主机会随机等一段时间后,再重新发送该数据
实际在网络通信压力不大的时候发生碰撞的概率是不大的,不要小瞧计算机的处理速度,也不要小瞧网线传播数据的速度
每个主机如何判断该数据是否是发送给自己的?
在局域网中发送的数据实际叫做MAC数据帧,在这个MAC数据帧的报头当中会包含两个字段,分别叫做源MAC地址和目的MAC地址
每一台计算机都至少配有一张网卡,而每一张网卡在出厂时就已经内置了一个48位的序列号,这个序列号被称之为"MAC地址",这个MAC地址是全球唯一的
在局域网中进行通信的时候,每一个主机在收到一个MAC数据帧后,都会提取该MAC数据帧的报头,找到对应的目的MAC地址与自己的MAC地址进行比对。若该MAC地址与自己的MAC地址不匹配,则直接将该MAC数据帧丢弃,只有MAC地址匹配时,该主机才会将该数据帧的有效载荷继续向上进行交付处理
扩展:
单向数据发送: 主机发送数据帧时,将数据帧当中的目的MAC地址指定为某一台主机,此时每台主机对数据帧进行识别后,最终只有那台指定的主机会将该数据帧向上交付进行处理
局域网内进行数据广播: 主机发送数据帧时,将数据帧当中的目的MAC地址设置为全1,此时所有主机收到该数据帧后都会对该数据帧进行处理
与碰撞相关的一种局域网攻击机制
若局域网内的某台主机一直向该局域网内发送一些无用的数据,那么其他主机一发数据就会产生碰撞,此时该局域网也就瘫痪了,这实际就是局域网本身的一个攻击原理。但需要注意的是,这台一直发送垃圾数据的主机,必须要通过某种方式绕过"碰撞避免"算法,否则当其发送的数据产生碰撞后,该主机自己也会执行“碰撞避免”算法
5.2 跨网络的两台主机通信
局域网之间都是通过路由器连接起来的,因此一个路由器至少能够横跨两个局域网。而这些被路由器级联的局域网都认为,该路由器就是本局域网内的一台主机,因此路由器可以和这些局域网内的任意一台主机进行直接通信
比如局域网1中的主机A想要和局域网2中的主机H进行通信,那么主机A可以先将数据发送给路由器,然后路由器再将数据转发给局域网2当中的主机H
采用不同通信标准的两个局域网内的主机通信
若路由器级联的两个局域网采用的是相同的通信标准,那么通信过程大致与上述一致。但被路由器级联的局域网可能采用的是不同的通信标准,比如局域网1采用的是以太网,而局域网2采用的却是令牌环网
由于以太网和令牌环网是不同的通信标准,给数据添加的报头也是不一样的,因此令牌环网中的主机无法对以太网当中的数据帧进行解包
这种情况实际是由路由器来处理的,路由器是工作在网络层的一个设备,可以认为路由器当中的协议栈是下面这样的
此时当数据要从局域网1发送到局域网2时,路由器收到局域网1的数据后,会先将以太网对应的报头进行解包,然后将剩下的数据向上交付给网络层,在网络层进行一系列数据分析后,再将数据向下交付给链路层,此时在链路层当中就会给该数据添加上令牌环对应的报头信息,然后再将该数据发送到局域网2当中,此时该数据就能够在令牌环网当中传输了
路由器为什么能够“认路”?
一个路由器可能会级联多个局域网,当路由器需要将一个局域网的数据转发到另一个局域网时,路由器如何知道该数据应该转发到哪一个局域网的呢?
路由器是通过IP地址来确定数据的转发方向的,公网上的每台计算机都有一个唯一的IP地址,而在数据向下进行封装时,在网络层封装的报头当中就会包含两个字段,分别是源IP地址和目的IP地址
当路由器需要将一个局域网的数据转发到另一个局域网时,在路由器的链路层会先将数据的在当前局域网对应的底层报头去掉,然后将剩下的数据向上交付给网络层,此时在网络层就可以获取到该数据对应的目的IP地址,然后路由器就可以根据该IP地址在路由表当中进行查找,最终就能够确认该数据应该发送到哪一个局域网
屏蔽底层的差异
IP地址的存在除了帮助数据"路由"以外,还可以屏蔽底层网络的差异。对于通信主机双方的IP层及其往上的协议来说,并不需要关心底层采用的是以太网还是令牌环网,只要填写了源IP地址和目的IP地址就能够将数据发送出去,因此现在主流的网络也被称为"IP网络"
这种类似的技术还有:
虚拟地址空间:屏蔽了内存之间的差别,让所有的进程看到的都是同一块内存,并且这块内存的布局都是一样的
一切皆文件:通过文件结构体和函数指针的方案,以对待文件的方式对待某些资源
六、网络中的地址管理
6.1 IP地址
IP地址是在IP协议中,用来标识网络中不同主机的地址
对于IPv4来说,IP地址是一个4字节,32位的整数
通常也使用"点分十进制"的字符串表示IP地址,如192.168.0.1,用点分割的每一个数字表示一个字节,范围是0-255
IP协议有两个版本:IPv4和IPv6。IPv4用32个bit位来标识IP地址,IPv6用128个bit位来标识IP地址
理解源IP地址和目的IP地址
因特网上的每台计算机都有一个唯一的IP地址,若一台主机上的数据要传输到另一台主机,那么对端主机的IP地址就应该作为该数据传输时的目的IP地址。但仅仅知道目的IP地址是不够的,当对端主机收到该数据后,对端主机还需要对该主机做出响应对,因此端主机也需要发送数据给该主机,此时对端主机就必须知道该主机的IP地址。因此一个传输的数据当中应该涵盖其源IP地址和目的IP地址,目的IP地址表明该数据传输的目的地,源IP地址作为对端主机响应时的目的IP地址
在数据进行传输之前,会先自顶向下贯穿网络协议栈完成数据的封装,其中在网络层封装的IP报头当中就涵盖了源IP地址和目的IP地址。而除了源IP地址和目的IP地址之外,还有源MAC地址和目的MAC地址的概念
6.2 MAC地址
MAC地址用来识别数据链路层中相连的节点
长度为48位,及6个字节,一般用16进制数字加上冒号的形式来表示(如08:00:27:03:fb:19)
在网卡出厂时就确定了,不能修改。MAC地址通常是唯一的(虚拟机中的MAC地址不是真实的MAC地址,可能会冲突,也有些网卡支持用户配置MAC地址)
大部分局域网都是以太网标准,其中 ether 对应就有"以太"的意思,而 ether 后面的这个地址就是当前云服务器所对应的MAC地址。但实际云服务器上的MAC地址可能不是真正的MAC地址,该MAC地址可能模拟出来的
理解源MAC地址和目的MAC地址
大部分数据的传输都是跨局域网的,数据在传输过程中经过若干个路由器,最终才能到达对端主机
源MAC地址和目的MAC地址是包含在链路层的报头当中的,而MAC地址实际只在当前局域网内有效,因此当数据跨网络到达另一个局域网时,其源MAC地址和目的MAC地址就需要发生变化,因此当数据达到路由器时,路由器会将该数据当中链路层的报头去掉,然后再重新封装一个报头,此时该数据的源MAC地址和目的MAC地址就发生了变化
在图中主机1向主机2发送数据的过程中,数据的源MAC地址和目的MAC地址的变化过程如下:
数据在传输的过程中是有两套地址:
源IP地址和目的IP地址,这两个地址在数据传输过程中基本是不会发生变化的(存在一些特殊情况,比如在数据传输过程中使用NET技术,其源IP地址会发生变化,但至少目的IP地址是不会变化的)
源MAC地址和目的MAC地址,这两个地址是一直在发生变化的,因为在数据传输的过程中路由器不断在进行解包和重新封装