前言: 在本节几乎不讲任何网络协议的系结, 只是将网络的概念搭建起来。本节将会讲到网络的一些专有名词, 概念, 以及网络的结构划分等等。 主要是带大家做一下前期知识的铺垫。 下面, 开始我们的学习吧!
ps:本节内容因为是网络的开始, 所以对于linux系统部分的要求不高。 只需要大概了解冯诺依曼体系结构即可。
目录
认识网络
认识网卡
认识协议
网络分层
软件分层
光电信号
网络分层的原因
打电话例子
网络分层的理解
应用端如何把数据发给对端
以太网通信
一个故事
一个原理
如何正确看待局域网
认识网络
认识网卡
到目前为止我们所做的编程都是单机的,但是一开始我们的计算机只是用来作为军事用途的。 可以说, 当时的大多数实验室, 比如说著名大学的各大实验室。 里面的人并不是一个, 所有电脑有很多。 但是当时的每一个人的电脑都是相互独立的, 所以每一个人使用计算机关注的点是不一样的。 就比如说我们学校的老师, 有一些老师是要获取同学们的学习的数据, 有一批老师是要获取同学们的上课数据的。 这些要获取数据的人的根本目的就是要把数据获取准确。
但是有一些老师是汇总同学们的学习数据以及获取同学们的学习的上课数据, 然后对学生的学习状态进行评估。 所以我们会发现这一批数据, 有人收集数据, 有人检测数据上的准确性。 也有人会基于数据做各种各样的决策, 做各种各样的动作。 所以这个场景就告诉我们——这个世界上的人是都要基于数据做各种协作的!
所以, 网络的产生是必然的。 当人们需要协作, 就比如小a, 小b, 小c。 其中小a是获取同学们的数据的。 小b是拿到小a整理的表格, 然后就开始检验其中的准确度, 然后就交给小c。 小c是来决策的, 对于每一位同学做处理。 因为三个人要协作, 所以一个人做完工作后一定是交给另外一个人的。 可是我们的电脑是独立的, 所以这些人们就想办法将多台计算机链接起来——所以, 网络的产生是历史的必然。
所以人们就搞了一台机器作为一个服务器, 人们将数据发送到这台机器上面, 其他人想要获取数据直接从服务器上面拉取就可以了。 所以这些电脑就相当于用线链接起来。 如同下图:
所以过去呢, 我们各大高校的实验室就都引进了这种小型网络, 每个实验室内部的计算机都能够链接起来。 但是实验室与实验室之间, 学校与机构之间有没有可能要合作呢? ——肯定是会有的, 所以这就要求一个区域的子网和另一个区域的子网能够连接起来。 所以呢, 随着历史的推动, 各大实验室的子网就逐渐集连起来, 这就是子网的集联, 会构成更大的网——这就会引发一些其他的问题,比如说距离的问题, 比如说定位的问题, 这些后面会讲到。
问题是我们各个实验室进行数据传输的时候, 我们并不知道我们实验室的数据要发送到另一个实验室的哪台机器上面。 所以就需要有对各台主机的定位功能, 比如mac地址, ip地址等等。
然后随着各种问题的出现, 为了解决这些问题, 我们的交换机, 路由器就都产生。如同下图:
然后呢,当全世界的局域网由路由器连接起来的时候, 这个就是广域网。
认识协议
认识协议,协议是一种约定——》计算机里面因为数据长距离传输, 所以他的传输成本就非常的高。 就比如距离边长了, 信号的衰减就成了问题。 所以经过长距离传输的时候是需要一些协议的。 就比如我们打电话, 我们打电话的规则是打电话的时候如果对面不接电话就不花钱。那么我们如果想办法, 和我们的朋友约定好暗号。 假如我们的电话响一声就是和我们问好, 假如响了两声就是叫我们出来玩, 响三声就是要接通电话细谈。 那么这样是不是就能够降低成本? ——也就是说, 通过协议, 是可以降低沟通的成本的, 通过双方约定的方式, 来降低沟通成本。 提高沟通的效率, 降低成本。
那么, 在计算机领域, 这个协议解决的是什么问题呢? 那么我们先来看一下计算机通信的时候有什么问题。 因为协议, 归根结底是根据问题来定制的。
- 如何处理发来的数据。——应用问题
- 长距离传输的数据丢失的问题。 ——技术问题
- 数据进行转换的时候如何定位主机的问题。 ——技术问题
- 你怎么保证你的数据能准确到达下一个设备。——技术问题
那么我们的发送方有上面的问题,我们的接收方同样有上面的问题。 所以我们是不是就必须在双方的机器上面把每一层的对应的问题都要解决。 如何做呢?
就是每一层都要设置对应的协议!各自解决各自当前层的问题。 就比如最底层, 就是数据链路要解决的。 倒数第二层就是网络层, 是使用ip协议解决的。ip协议就是帮我们定义一台主机。 所以协议里面就一定有我们的原ip是谁, 目的ip是谁。 每台主机上面都有自己的ip地址, 没有ip地址是通信不了的。倒数第三层就是tcp协议, 在往上就是应用层, 也就是人们写的http, https, smtp, ftp等等协议。
其实说为什么会有上面的问题, 根本原因就是因为信息的传输距离边长了。
认识报文:当我们再给我们的同学寄快递的时候, 我们是不是写过一个单子? 这个就是所谓的快递单。 这个快递单的目的其实就是用来确定这个快递是给我们的。 到了网络里传输数据也要给我们传输这所谓的快递单, 但是在网络里这叫做协议!严格意义上来讲叫做协议的报头。 所以我们发送信号, 都想要在原本想要发的东西之上多发一点。 这里面有什么呢? 这个报头其实就是一个结构体。 在结构体里面我们把字段规定好, 我们可以定义各种变量对象类型。 我们把我们想要发的数据拷贝到结构体后边,这样我们就构建了一个报文!——所以说, 协议是双方的约定, 它的最终表现形式就是结构体对象!
网络分层
软件分层
我们在谈网络分层之前, 先来谈谈软件分层。
什么是软件分层呢?软件分层分为逻辑分层和数据结构上面的分层。 我们使用的linux本身就是分层的, 从底层硬件到驱动, 再到操作系统, 再到系统调用接口,再到动静态库这就是分层的。
但是具体是怎么分层的呢?我们在学c++的时候, 我们学习过继承。 但是我们没有讲过继承多台在软件方面的意义。 继承和多态在软件方面的意义其实就是在做软件分层。 基类就是在上层, 子类的各种实现就是在下层。 我们改下一层并不影响上一层。 这就是软件分层。
我们之前讲过VFS, 我们给每一个文件struct file, 这里面包含函数指针, 这个函数指针指向底层的不同硬件的方法。 这样上层就可以统一以文件的方法访问硬件了。
光电信号
我们的计算机里, 传递的其实就是光电信号:
计算机终端光电信号, 通过频率和强弱来表示0和1这样的信息, 要传递各种不同的信息, 就要约定好双方的数据格式。 我们要知道, 计算机的厂商有很多, 计算机操作系统也有很多,计算机网络硬件设备, 还是有很多。 如何让这些不同的计算机之间能够互相顺畅的通信? 就需要有人站出来, 约定一个共同的标准大家都来遵守, 这个就是网络协议。
网络分层的原因
而我们的网络是分层的, 原因如下:
- 因为我们的网络软件规模太大了, 所以想要将各板块都解构出来。 ——技术上的原因
- 协议是用来解决问题的。 问题有很多, 问题是层状的, 所以协议定义出来也就是层状的了。——实际情况
- 问题是解决一个主机到下一跳路由器之间的交互。 然后就是解决路由器问题。 再然后就是数据传输的可靠问题。——具体情况
打电话例子
我们再来讲述一个例子, 这个例子是我们日常的打电话的场景。
我们日常打电话, 其实是通过接口和电话机沟通。 然后电话机底层根据协议帮我们把信息传递给另一个电话机。 然后另一个电话机再通过接口将信息传达给上层的用户。 这个过程的本质其实是人和电话直接沟通。 在逻辑上, 我们认为人和人,电话和电话在沟通。
我们在打电话的时候, 先说一声,“喂”。——这一声“喂”, 其实就是语音层通信的一次握手。 电话和电话之间的协议, 人不关心。 人与人之间的沟通语言, 电话不关心。这就是层与层之间的低耦合, 高内聚。
ps:层状结构有一个好处, 好维护, 一层出问题,这个问题只会影响这一层本身。 调整这一层就可以, 不会影响下一层。
网络分层的理解
OSI是在网络协议定制上权威的机构, 网络分层的标准都是由OSI来定。 OSI根据网络分层的需求,将网络分成了七层模型。 这七层自底向上为:物理层、数据链路层、网络层、传输层、会话层、标识层、应用层。
因为有些层太大了, 不可能写到操作系统当中, 所以工程实践中, 我们的网络协议层状结构严格意义上来讲, 最终被划分为了5层协议: 叫做物理层、数据链路层、网络层、传输层和应用层。 会话和标识这两层并没有在协议当中体现出来。 但是, 这两层在写代码的时候, 写多了, 就能看出这两层其实在代码中是有的。 如果没有, 就很容易出现问题。 会话和标识层内核当中没有被发现, 而是被上层用户去实现。
在操作系统当中, 最重要的两层协议, 是网络层和传输层。 而传输层最具代表性的协议叫做tcp, 网络层最具有代表性的协议叫ip。
- 物理层, 主要负责光电信号的传递, 我们同学能感知到的一些物理层的设备或者说电气特性。 比如说以太网当中的双绞线。比如光纤, 这个光纤一段可以插在猫上, 有了猫之后, 猫的另一端可以插有线的水晶头, 连网线。 集线器:光电在传输的时候, 会随着长度的增加一定会发生衰减。 会发生衰减, 就意味着广电传输一定有着半径或者说天花板。 所以为了我们的数据能够传输的更远, 就有了我们的集线器这样的设备。 集线器在物理层面上主要用来做信号放大。 比方说此时信号已经很衰弱了, 但是通过集线器就直接可以把信号给放大。 然后就能传送到更远了。
- 数据链路层, 比方说我们链接着家里的路由器, 我想访问抖音, 但是访问抖音的前提是得把我们的请求交给我们家里的路由器。 然后家里的路由器再将请求发送出去。 所以, 数据链路层主要是解决同一个局域网当中, 两台设备之间的数据之间的传递和识别。
互联网是由无数个子网构成的, 所以任何一个子网能够通信了, 子网和子网之间有一到两个设备也能通信。 数据就能发生跳转, 能传递。
就比如上面三个黑色框框, 就是三个子网。 每两个子网之前都可以通过一个路由器链接起来。
所以上面两个点之间一定是可以走通, 关键是我们为什么能够准确地定位到两个点呢? 这就是主机定位的问题以及数据包路由器的问题。 这两个问题是由网络层来解决的, 在网络层当中, 最重要的设备就是路由器。 所以, 路由器主要是工作在网络层。
- 传输层:解决数据通信的可靠性问题和数据安全的问题。
- 应用层:应用层还是回答应用的问题。
OS学了, 网络协议栈也学了。网络协议栈和我们之前学习的OS有什么关系呢?
我们看上面一张图片。
首先, 数据链路层是软件, 是在各种软件驱动内部实现的。
然后传输层和网络层是在linux内核中真正要实现的, 是linux内核中的模块。 所以, 网络层和传输层是操作系统的一部分, 也就是说, 网络层和传输层, 就是操作系统!所以, 为什么学习OS, 因为网络层和传输层就是在操作系统内实现的。
最后应用层, 我们知道我们刷抖音, 看新闻。 不就是用户通过我们的网卡这样的设备把我们的请求, 把远端传来的数据信息,拉取到本地吗? 本质是不是用户在直接访问硬件啊。 而printf的本质不就是把我们的消息打印到显示器上面吗。 我们的读取磁盘, 不就是把内存中的数据拷贝给磁盘吗? 今天我们刷抖音是通过网卡拿到数据请求, 然后网卡交给用户, 用户就能看到了。 所以网络通信的根本也是在访问硬件!!!
我们还要知道, 我们的用户想要访问网卡, 就必须贯穿整个操作系统。 而贯穿整个操作系统, 操作系统又不想让用户直接访问操作系统内部的代码和数据, 所以, 我们对应的系统在网络层就必须给我们提供系统调用!!!
所以, 我们对应的系统在网络协议中就必须给我们提供系统调用!!!
所以, 开发者根据系统调用, 就能开发出各种各样的应用协议。 来供用户使用, 比如说http, https, smtp, DNS——这就叫做应用层。
全球的操作系统, 可能在OS内核实现的进程管理等等不一样。 但是它的网络协议栈一定是一样的, 否则他就没办法入网!
即便是手机和电脑, 两者的操作系统很明显是不一样的:
我们的手机和电脑也是可以通信的。 即便操作系统不一样, 但是没关系。 操作系统各玩各的。 但是我们的网络栈一定是相同的。 所以手机给电脑发送消息, 就是贯穿整个操作系统,然后电脑的操作系统自底向上接收消息。 未来我们的层与层之间逻辑上就是直接通信!!!
未来我们每一层就有相同的结构体, 每一层就有相同的字段。 所以未来我们层与层之间, 就从逻辑上认为自己在和对方的那一层直接通信。 所以我们就能理解——网络通信的本质就是贯穿整个协议栈的过程。 无非就是从上往下, 或者从下往上。
应用端如何把数据发给对端
了解这个这个问题,我们要根据一张图, 就是下面这张图:
经过时代的更迭, 时代选择了最重要的局域网协议, 以太网。 还存在现在比较重要的网络通信协议无线LAN。(以太网是主流, 是属于局域网通信标准的一种。) 我们上图是两台局域网的主机, 在同一个以太网之下。 我们图中右上角有一根用户进程, 画了一根横线。 这根横线以下叫做内核。 横线以上叫做用户。
那么, 怎样把数据发送给对端的呢? 网络协议栈的层状结构中, 每一层都有协议。 所以, 我们的发送方, 发送一个你好。 当我们发送你好的时候, 要把对应的协议信息添加上, 对方的对应层才能收到。 那么, 什么叫做协议呢?协议就是一种约定。 也就是我们要发送的数据要添加一个报头,而报头就是双方都约定好的结构体类型。 在大部分情况下, 都是结构体, 在少量的情况下, 都是由很多很多的固定格式的字符串构成的。 我们的信息发送给对方, 被对方收到, 那么对方就能根据对应的报头进行字段解析。比如:
- 我们的应用层的协议规定, 信息都要有版本, 所以这个时候就要给信息加上版本。
- 然后信息的可靠指标之一:就是信息是有序的。 这就要求传输层和对方的传输层进行协商。 所以传输层也要有自己的报头, 给每一个信息携带上序号。 保证有效性, 所以传输层也要有自己的协议!!!
- 然后信息到了网络层, 到了网络层我们就又有网络层的报头字段, 假如这里面写src, dst。 那么这个时候我们的信息就已经有三个报头字段了:一个版本, 一个序号, 一个src,dst。 然后对方解析自己的同层报文的时候, 就能知道, 对方这个报文是发给我的。
- 同理, 我们的报文再继续向下交互, 那么他就得添加数据链路层的协议。
我们把这个过程叫做数据的自顶向下交付, 就完成了一次封装的过程。
我们把每一层添加到这种不同的协议字段, 叫做每一层的报头。 ——即, 每层都要添加报头。
报头 = 报头 + 有效载荷。 比如我们的网络层, src, dst就是网络层的报头,剩下的就是有效载荷。 比如传输层, 序号就是报头, 剩下的就是有效载荷。
当我们的数据链路层利用网卡发送报文的时候, 一定是对方的网卡拿到了数据, 网卡拿到了数据之后,就把数据交给操作系统。 然后才有了数据链路层, 网络层, 传输层以及应用层。 为什么网卡把数据交到操作系统, 也就是内存里面呢?因为冯诺依曼体系规定的。 规定, 外设拿到数据, 想要拿到cpu处理, 就必须交到内存里。
同层协议, 我们的结构体是一样的。 所以就能认识对方的报头。 所以我们的接收方,接到了报文之后, 他就能区分哪部分是报文, 哪部分是有效载荷。 所以链路层的驱动程序(以太网驱动程序)就要把报头作分离。 分离之后怎么办呢, 就将有效载荷交给上一层。 所以, 对方有什么, 这边收什么。 到了上层网络层之后,就还是有三个报头字段, 其中src, dst是网络层想要的, 其他的都是有效载荷, 将报头分离后, 有效载荷继续传给上一层传输层。 以此类推, 直到用户的手里就是我们的汉语协议!!!
我们还能发现, 当我们的数据包到达目标主机的时候, 从底向上的交付的过程, 其实就是去掉报头的过程。 我们把它, 叫做解包。(还有一个叫分用, 后面谈) 而通信的过程, 本身就叫做不断地封装和解包的过程!
我们后面学习网络, 无外乎就是学习每一层的报头和每一层协议的特点!整个逻辑就是封装和解包。
扩展:
- 第一个问题:我们把一碗水倒到水桶里, 然后后来我们把碗里的水和水桶的水分开。 那么我们就分不开了, 但是我们用一个瓶子装着这碗水扔到水桶里, 我们想分开, 就直接把瓶子拿出来就可以了。 意思就是说, 我们每一层的解包和分用, 他的每一层协议, 在封装的时候, 就要考虑未来怎么更好的解包。 ——几乎任何层的协议, 都要提供一种能力, 将报头和有效载荷分离的能力。
- 第二个问题:几乎任何层的协议都要在报头中提供, 决定将自己的有效载荷, 交付给上层的那一个协议的能力。 ——这种能力叫做报文的分用的能力。
有了上面这两点, 面对封装和解包, 才不会困惑。 并且他们是最大部分协议的共性。 未来我们学习具体协议的时候, 我们都要考虑这两个问题。
以太网通信
多台主机在以太网上, 是怎么通信的? 对于以太网通信, 我们要将一个故事, 一个原理。 而我们几乎可以肯定, 我们每台主机在局域网上,都有自己唯一的“标识”。
一个故事
这是一个教室:假如老师和同学们正在上课。 班级里面有很多的学生, 今天又一个人叫张三, 一个人叫李四。 如果老师叫张三站起来, 这时候是不是班级里面的同学都听到了这句话? 但是, 是不是只有张三会站起来? 为什么李四不站起来呢? 是不是因为同学们不光听到了老师的报文, 而且对老师的报文的信息做提取!提取出来消息后发现与自己无关, 然后就把刚刚说的话都丢到脑后了。
然后张三就说, 老师, 我昨天就给你了啊, 你忘记了。 然后这个时候, 是不是全班的同学都听到了张三的话。但是对于其他同学, 比如李四来说。 他会不会说,不好意思我忘记了。 不会的, 因为张三不是和他说的话, 而是和老师说的。 所以,每一个人继续把这个报文做丢弃, 所以我们就认为张三和老师完成了一次通话!所以, 这个故事当中, 老师以为他在和张三进行沟通, 张三也以为他在和老师沟通。 但是, 中间有一大堆的吃瓜群众。 这种通信方式, 就叫做局域网或者叫做以太网通信原理。
一个原理
这里面, 每一个小格子, 就叫做一个主机。 没有给主机都挂到了一根网线上面, 那么这些主机都叫做在同一个局域网。 在局域网的这些主机, 就相当于我们班级里面的每一名同学。 我们同学, 为了标记主机, 所以我们每一个同学都有一个mac地址。 我们每一台电脑, 都有一个网卡, 每一个网卡在出厂时,都有一个48比特长度的序列号。 并且这个序列号是全球唯一的。 硬件上呢, 每一个网卡都有它唯一的标识, 网卡的序列号信息, 我们把它叫做mac地址, 当我们的操作系统在启动的时候, 操作系统会读取网卡里面的属性信息, 其中就会获得到网卡的mac地址。
假如说, 几天我们的H1想要和H10互相通信, 那么就有一个数据帧, 如下:
然后将这个结构发送到网络里面, 我们的问题是, 这个数据帧, H2, H3...它们收到了吗? ——我们在局域网当中发送一条消息, 这条消息会被局域网当中的所有的主机都收到。 (这个收到是在网卡, 也就是硬件层面上)然后收到之后, 大家继续在数据电路层做分析, 做处理。
然后其他主机都会在同一时间对这个报文做解析, 然后报头和有效载荷做分离。 然后对报头做分析, 分析这个报头的目标是M10, 可是如果主机不是M10, 那么这个报文, 直接就丢弃了。 这个判断工作是在那里工作呢? 是在我们的数据链路层, 也就是这个以太网驱动层做的。 一旦判断这个报文不是发给他的, 那么他的整个报文就丢弃了。 那么请问, 上层, 知不知道曾经收到过这个报文呢? ——这个是不知道的, 所以就好像这个主机没有受到过这个报文一样, 因为它在底层就被丢弃了。
如果主机是M10, 他分析报文是发给自己的。 然后他把对应的报文, 解析之后将报头交付给上一层, 交付给上一层之后就可以进行数据处理了。 这个就叫做局域网通信原理。
问题是, 如果在一个局域网之中, 有很多的主机都在发送消息。 那么这些消息, 就会发生数据碰撞问题。 ——以太网发生数据碰撞问题, 光电信号一旦碰撞, 波信号就乱了, 信息就混乱了。
所以, 想要搞掉一个局域网的方法很简单, 就是我们不断向局域网当中发送垃圾信息, 和正常信息进行碰撞。
其实, 在系统中有发送主机都要执行的碰撞避免的算法。 这个算法是由以太网的驱动程序自己定的。 ——原理就是, 既然发生了碰撞, 就等一会儿再发。 即, 延迟发送, 错峰出行!!!
安全问题:我们H1给H10发送信息的时候, 我们的信息是在局域网当中裸奔的, 我们的其他主机比如H2其实是能够拿到的。 而且确实拿到了, 只要他愿意, 他也可以把数据报文传上去给上层看。
正常情况下, 我们的网卡接收到不是自己的报文就丢弃了。但是我们的网卡有一种工作模式——混杂模式(本来是正常模式), 就是抓到报文后不丢弃, 而是传给上层。
信息传输安全问题是有的, 关键在于我们发送的问题从哪来, 一般我们的数据都是从顶层来的。 我们可以在最上层对数据进行加密, 加密后才给我们的以太网。 所以, 即便被其他人抓到了, 但是只要我们加密了, 其他人也看不到。我们最怕的是从头到尾我们发送的数据都是落着的。
如何正确看待局域网
整个局域网中, 任何时刻, 只允许一个主机向局域网当中发送消息。 所以, 局域网是所有主机的共享资源!而任何时刻只允许一个, 不就是我们的主机保证能够互斥访问。 他的策略不是通过加锁, 二十一但发送错误, 那么我们重新发。 局域网可以看成多态主机共享的临界资源。 未来, 向网络里发送, 进行网络读写, 不也是进程在进行网络读写吗? 所以每台主机的背后就是进程, 而碰撞不就是我们在写的时候别人也来写了吗? 所以, 系统网络不分家。
——————以上就是本节全部内容哦, 如果对友友们有帮助的话可以关注博主, 方便学习更多知识哦!!!