文章目录
- 重新看待计算机体系结构
- 软件分层的思想
- 网络中的分层
- 协议的理解
- 局域网的理解
- MAC地址 && IP地址
- 报头的作用
- 端口号(port)
重新看待计算机体系结构
计算机由硬件组成,而不同硬件之间要怎么通信,或者说要怎么进行数据的传输?在计算机中,所有的数据传输都依赖于“线”,每块硬件之间都有连接彼此的线,数据就是通过这些线,在不同硬件之间流动。在一台计算机内部,硬件之间的距离比较近,所以连接硬件的线比较短,但是由于数据的跨设备传输需求越来越强烈,不同的计算机设备之间也要进行通信,而数据通信的本质是数据通过“线”向不同的设备流动。将不同计算机设备的网卡用“线”连接起来,使数据从网卡出发,通过“线”流动到另一台设备的网卡上,数据通信就完成了,但是这个通信过程中用来通信的“线”比较特殊,它可以是无线LAN,或者是一条长长的网线,总之通过这个“线”,数据完成了通信。而所有网络的概念都是建立在“线”的基础上,不同计算机设备的距离有远有近,但是相比于计算机设备内部的“线”,不同设备用来通信的“线”是非常“长”的。因为“线”的变长,通信面临的问题也随之多了起来:通信数据的可靠性,通信效率,如何找到通信的对象?,而网络相关的知识都是为了解决“线”的变长带来的问题。
通过对计算机体系结构的重新理解,我们可以认为计算机内部硬件之间的通信是一种网络(所以,学习计算机时,我们很早就接触到了网络,只是因为我们的对网络的理解角度不同,所以没有察觉),而不同计算机设备之间的通信也是一种网络,后者是我们通常认为的网络,我们所需要学习的网络也是后者。
软件分层的思想
学习Linux到现在,我接触到了两个软件分层的例子:虚拟内存与Linux的虚拟文件系统,这两个软件分层的运用都十分的经典。对于虚拟内存:进程不直接访问真实的物理内存,而是在访问物理内存之前访问虚拟内存,通过虚拟内存可以拦截非法的内存访问,保护真实的物理内存,并且极大的提高了系统的整体运行效率。对于虚拟文件系统,系统向下封装了硬件的驱动接口,向上提供了统一的使用接口,使系统可以用相同的方式调用软件和硬件,具体的细节我在Linux文件系统中有所讲解。虽然例子不多,但是通过这两个例子足以体现分层思想在计算机领域的伟大之处,甚至有说法:没有什么问题是不能通过“加一层”解决的,其中的“加一层”指的就是对软件分层。软件分层的思想在计算机的方方面面都有体现,
计算机网络的设计同样也使用了软件分层。网络世界是层状的,在同一层的通信的双方不用关注通信底层的实现细节,只管进行通信,但是同层之间的通信一定要遵守一定的协议!
协议:即双方通信前互相约定的规则,比如规定我要写入的数据大小,你读取时也需要读取同样大小的数据,我们的通信才能正确的进行下去,协议即规则,通信的规则,不遵守这个规则就无法通信。但是通信只建立在协议的基础上就可以吗?我遵守了规则,正确的读取了你写入的数据,但是我无法解析或者无法读懂你写入的数据,这样的通信就是无效的。所以除了要遵守协议,我们还需要注意表达信息的方式。比如两个人打电话,一个人在讲话,另一个人就必须聆听,这是一个协议,双方都遵守了,但是一个人在讲英语,另一个人却听不懂英语,并且它只会汉语,但是前者又听不懂汉语,在这个场景中,虽然双方都遵守了协议,但是因为信息的表达方式不同,导致了通信的失败,所以通信时除了遵守协议,还需要注意表达方式,通信双方都必须理解彼此的表达方式。从这个例子中也能说明一个现象:通信时,同层通信的双方都认为是在与对方直接通信,什么意思呢?我打电话给你,我当然认为我和你在对话,你当然也是这样认为,但是事实并不是这个样子的,我只是在与一部手机通信,手机接收到了我的声音,将声音转换成信号进行转发,使对方的手机接收到信号,然后再解析这些信号,转换为人能听懂的语言。所以你看,手机做了这么多的工作,通信才能进行下去,但是你和我打电话时关心这些吗?根本不关心,我们只是不停的在与对方交流,我们都认为我们在与对方直接的进行通信,同理,处于同一层的手机也是这样在与对方直接通信
网络中的分层
网络的本质是通信,我们将通信模型大致分为五层,从上到下分别是应用层,传输层,网络层,数据链路层,物理层。上图是通信与计算机系统之间的关系,操作系统作为硬件与用户之间的中间层,起到承上启下的作用,用户在操作系统之上使用计算机,用户通过一些可执行程序或可链接的库文件,如shell,指令,动静态库调用了系统提供的接口,通过系统提供的接口我们能间接调用操作系统,我们在操作系统之上还能调用通信模型中的应用层,总之我们对计算机的所有操作都会贯穿操作系统。通信模型中的传输层与网络层则隶属于操作系统,我们在应用层的操作会被操作系统接收,因为要进行通信,操作系统会对我们的操作进行封装,使通信能够进行。而数据链路层是属于操作系统中驱动程序的一部分,数据链路层可以驱动底层的通信硬件进行工作。总之,通信模型只是计算机设备的一部分。我们操作计算机本质是在对其硬件进行操作,但是计算机的硬件何其复杂,想要直接对这些硬件进行操作成本太高,所以我们创造了操作系统,让操作系统管理这些复杂的硬件,我们只需要学习操作系统就可以操作计算机了,但是学习成本还是高,所以我们对操作系统进行了封装,使操作系统只暴露出简单的接口,我们用户对计算机的操作就变成了对操作系统接口的操作。而我们能直接使用的就是一些可执行程序,包括通信模型中的应用层,这些程序会调用操作系统提供的接口,间接调用操作系统,最后操作系统将驱动计算机硬件进行工作。经过这样的分析,我们知道所有对计算机的操作都必将贯穿操作系统,自顶向下的递达物理层,调用计算机设备的硬件。
所以在通信模型中,用户在应用层的操作,将驱动数据从应用层出发,然后一路向下,穿过传输层,网络层,数据链路层,最后到达物理层,这个传输过程是由计算机体系结构决定的。当然,除了我们能向硬件传输数据信息,硬件也能向我们反馈数据信息,这时的数据信息就是自底向上的流动了。最后,总结一下,在通信模型中,由于计算机体系结构的决定,数据的流动方向总是自顶向下,或者自底向上,我们所有与计算机的交互,都遵守这样的流动方向。
回到网络,在网络通信的过程中,我们需要调用网卡这个硬件设备向外传输数据,所以数据先自顶向下的流动到网卡,网卡将数据传输给另一台设备的网卡,该设备的网卡就会自底向上传输数据,数据流动到用户层,用户才算接收到这些数据,因为用户位于用户层之上。这是数据在网络通信中的流动方向,自顶向下,自底向上,处于用户层的用户在通信时,只是将通信数据交给计算机,丝毫不关心数据是如何通信的,通信双方只用专注于通信,接收通信数据,发送通信数据,这使得通信双方产生了一种直接与对方通信的“假象”。以网络购物为例,我们下单商品,过几天商品就会被送到我们的手上,在商品运输的过程中,我们不关心包裹是被谁派送的,现在派送到哪,从哪里派送来的?我们只关心最后收到的商品是否有问题,但是在我们收到商品时,除了我们需要的商品,商品上还有一张快递单,虽然我们不需要快递单,但是我们可以通过快递单确定包裹的信息,快递单就是一种数据,快递公司,快递小哥,快递驿站只有通过快递单才能将包裹送到我们手中。由此可见,虽然我们不需要快递单,我们只关心快递是否有问题,不关心快递是如何派送的,但是快递单却是运送过程中不可缺少的数据。
协议的理解
在网络通信中,快递单就是一种协议数据,通过协议数据,通信才能正确的进行。我们常说的网络协议体现在两个方面:一是数据,协议由数据体现,正如快递上的快递单,如果协议有一个标准,即使用统一的协议,一个快递就可以被多个公司正确的运输,因为这些公司也遵守了这些协议,这是协议统一对通信的好处(题外话)。二是逻辑,协议中的数据保证了数据传输的方向是正确的(快递公司根据快递单上的消息运输快递),通信双方才能愉快的进行数据传输。因此,协议在通信过程中是十分重要的,可以说正是因为协议的存在,同层之间的直接通信的“假象”才可能存在。有了协议的认知,我们再对网络通信的过程进行重新理解,数据被用户发出,从应用层出发,计算机体系结构决定,数据要向下流动,流动过程中通信模型的每一层都会对数据进行封装,打包,为数据添加协议数据,以保证通信能正常进行,所以最后硬件层的网卡发出数据,数据已经被添加了多层协议,带着这些协议数据,数据被对方硬件层的网卡接收,我们知道数据会自底向上传输,最终呈现给对方,那么在向上的层与层之间的传输中,每一层会识别属于自己的协议,然后将协议数据剥离,再向上传输,而数据最后到达应用层时,应用层将属于自己的协议数据拆解,拆解后的数据与用户发送的原始数据完全相同,最后对方收到的数据是一份完全相同的数据,所以通信会产生自己正在直接与对方通信的“错觉”。
局域网的理解
两台设备通过这样的方式进行通信,当通信的设备达到一定规模时,就组成了局域网,局域网中通信设备的数量虽然达到一定规模,但规模还是较小。以太网是局域网的一种技术实现,以太网中,一台设备要进行通信,就需要向所有设备广播数据消息,但是只有指定接收的设备才会接收数据。这就有点像课堂上老师的点名,虽然所有人都知道老师点的名字,但是只会有一位同学站起来,其他人并不会站起,为什么?因为点的不是他们。以太网也是如此,所有设备都能接收到其他设备发送的数据,但是只有指定接收数据的设备才会接收数据。这也导致了一个问题,一台设备发送数据,所有人都能接收到,如果两台设备同时发送消息,数据就发生了冲突,我们把这种冲突叫做碰撞。以太网中的设备会识别碰撞是否发生了,如果发生了,发送数据的设备会选择其他时间再次发送数据
除了以太网,令牌环网也是局域网的一种技术实现,以太网中存在数据碰撞的问题,数据可以被所有设备看到,那么这些数据就是共享资源,根据我们对线程的学习,我们可以对线程加锁保证共享资源的安全性,在网络通信中,我们可以给设备赋予令牌,只要设备持有令牌就能向局域网中发送数据,并且令牌只有一个,由于令牌的限制,在令牌环网中不会发生数据碰撞的问题
MAC地址 && IP地址
要谈网络,首先我们要辨析这两个地址概念。比如你要去旅游,从黑龙江到山东,如果你选择了自驾游,那么你就需要先规划你的行车路线,首先你的目标地址是山东,你的源地址是黑龙江,然后呢,你可能选择先从黑龙江到吉林,再从吉林到辽宁…在行车的过程中,我们需要两组地址,一是不会变化的源地址与目标地址,二是会随着地点变化的上一站地址与下一站地址。两者的区别就是角度的不同,从整个过程来看,你的源地址与目标地址是不会发生变化的,但是从行车的一部分过程来看,你从黑龙江到吉林,从吉林到辽宁,这些源地址与目标地址是始终发生变化的。在网络通信中也存在着这样的两组地址
IP地址:用来标识广域网的源地址与目标地址的唯一性
MAC地址:用来标识局域网的源地址与目标地址的唯一性
IP地址描述整体,MAC地址描述局部。有了这样的认识,我们再一次理解网络通信的过程,数据从一台计算机的网卡发出,此时的数据已经被模型的每一层进行了协议打包,在网络层,数据会被添加IP地址,在数据链路层,数据会被添加MAC地址。被打包的数据最终会传输到目标IP的设备上,但是传输是一个漫长的过程,需要慢慢来,数据会先递达目标MAC地址,通过递达一个个目标MAC地址最终递达目标IP地址。
数据需要一步步的传输,需要更新MAC地址以明确下一步该往哪走,我们将更新MAC地址的过程称为转发,转发的工作由路由完成,路由设备连接了多台设备,知道这些设备的MAC地址,可以认为路由与这些设备处于同一个局域网中,数据需要从一个局域网到另一个局域网就需要路由的转发,而局域网的实现技术有很多种,每一种技术使用的协议都不相同,所以路由要支持多种局域网技术的协议,才能与这些设备处于同一个局域网中。数据通信时,先被路由接收,因为路由设备处于网络层(路由在数据链路层之上的网络层,因为路由的数据链路层要支持多种局域网协议),需要先解析数据的局域网协议,拿到有效的数据,接着分析得到数据的目标IP,路由在其局域网中进行查找,如果目标IP设备就在局域网中,路由会将数据在数据链路层进行再次封包,将目标IP的MAC地址作为协议数据的一部分添加到数据中,然后将数据向下传输,通过硬件将数据发送,数据就会被传输到目标IP设备的网卡中,目标设备将数据自底向上传输并解包,将数据呈现给用户,至此通信过程完成
在上面的通信过程中,我们加入了路由设备以实现不同局域网中的数据通信,一个个不同的局域网就构成了广域网,路由在广域网中起到转发的作用,是通信过程中的中转站,在路由设备以下,路由连接了不同的局域网,数据在不同局域网中所遵守的协议肯定是不同的,但是路由位于网络层,路由只会拆分和打包数据链路层的协议,也就是说数据在网络层之上都是相同的,因为数据被传输到网络层时,封装了应用层,传输层,网络层的协议,但是数据需要在不同的局域网中传输,需要经过路由的数据链路层协议的解包和封装,所以数据封装的局域网协议都是不相同的。但是在路由之上,发送设备和接收设备所看到的数据是完全相同的,因此在网络通信的过程中,网络层屏蔽了底层数据的差异,使网络层以上的数据以统一的形式呈现
报头的作用
同层传输的数据需要遵守协议,协议则体现在数据上,数据在被传输之前会被添加上一些数据,这些数据我们称为报头。我们知道协议不一定只有一种,同层传输的协议有很多,但是在解包时,要怎么知道解包后得到的有效载荷是遵守什么协议的?如果不知道有效载荷的协议就无法理解数据的含义,通信也就无法进行,但是这些担忧都将由报头解决,报头的作用有:
1.报头的某些字段将表明报头的具体范围,明确报头和报文之间的分界,使解包时得到的有效载荷是完整的
2.报头的某些字段表明有效载荷所遵守的协议,使得上层可以用正确的协议解析这些有效载荷
我们称解析数据的报文并将解包后得到的有效载荷传输给正确协议这个过程为分用
端口号(port)
但是通信的过程只是两台设备之间发送和接收数据吗?很显然只是这样接收数据并没有意义,因为数据需要被处理,处理数据的工作由进程完成,所以将数据传输到进程上,让进程使用这些数据,通信才是有意义的,因此通信的本质其实是进程间的数据传输。那么一台设备接收到了数据,要怎么将数据发送给进程呢(系统中的进程可是有很多的)?在操作系统中,每个进程都有一个端口号,数据通过端口号就可以发送给进程,端口号是一个2字节,16bit的整数)。但是端口号必须和进程满足一一对应的关系,即通过一个端口号只会找到一个进程,但是一个进程可以有多个端口号,通过不同的端口号找到的进程可能是同一个。端口号有点像文件系统中的文件名,硬链接只是创建文件名与inode之间的映射,通过文件名可以打开其映射的inode,并且多个文件名可以映射同一个inode文件,但是一个文件名不可能映射多个inode文件。
所以通过IP+port就可以确定广域网中的一个唯一的进程,通过IP确定广域网中唯一的主机,port确定主机上唯一的进程。那么这里就有一个问题,为什么不能使用进程的pid,而要使用进程的端口号进行通信,进程的pid不是也是唯一的吗?这是因为,使用端口号可以更方便的管理用于网络通信的进程,使网络通信的管理与进程管理解耦,并且使用端口号也从侧面说明了该进程正在进行网络通信。就像为什么你有身份证号,但是学校依然给了你一个学号,就是因为使用学号方便管理学生,使用身份证虽然也可以,但是使学校的管理与政府身份消息的管理进行强耦合毕竟不太好,并且学号可以说明你是一个学生,正在学校接收学习。所以操作系统需要使用端口号标识唯一的进程