网络发展
网络的发展可以从人与人之间的工作模式开始谈起, 人与人的工作模式反应了机器与机器的工作模式:
- 独立模式: 在网络发展的早期计算机间处于独立模式, 计算机之间相互独立
最开始计算机之间是独立运行的 , 数据之间的交互需要人用软盘等存储介质 拷贝过去, 一般涉及到"人"的操作效率都很底下.
- 网络互联: 多台计算机连接在一起, 完成数据共享.
把所有的主机通过网线连接到一起 , 然后设计一个服务器存储 人们工作所需要的数据, 这样就形成了局域网(LAN)的雏形, 我们可以通过服务器实现数据的共享.
- 局域网LAN: 计算机数量更多了, 通过交换机和路由器连接在一起;
为了实现局域网之间的互联, 我们需要路由器交换机这样的路由设备将网络连接起来.
对于路由器来说, 它的作用是连接子网和进行报文转发的; 在一个子网中, 随着主机数目的增加, 局域网发生数据碰撞的概率增加, 需要添加一个交换机.
- 广域网WAN: 将远隔千里的计算机都连在一起;
随后就要考虑城与城, 国家与国家之间的网络互联.
"局域网"和"广域网"只是一个相对的概念. 可以将一个国家的单个城市不同地区局域网组成的广域网, 看做是这个国家的局域网. 而不同国家的广域网, 又可以看作全球通信的局域网.
协议
我们要认识到: 计算机本身就是一种小型的网络结构, 在计算机的内部存在许多模块, 比如CPU,显卡,磁盘,网卡等硬件资源. 这些模块只有协同工作, 才能保证一台计算机正常运行. 模块间必定存在信息的传送. 在计算机中通过总线在各模块之间传输数据信息.
为什么要有协议
单个计算机模块间的短距离传输和网络的数据传输之间的区别是什么?
数据传输的距离变长了 ! 对于网络而言, 更多的都是长距离 的数据传输, 所以网络传输就会产生诸多的问题, 比如:
- 数据丢包怎么办?
- 一个网络中主机很多, 如何定位到单个目标主机?
- 数据如何经过诸多设备的转发仍能准确传输给远端目标机器
这些都是网络中各个层的协议要解决的问题.
什么是协议
协议本质是一种约定 . 人与人之间可以通过提前约定好的协议来通信, 在计算机中也是一样, 比如说client 和 server 进行通信. 提前先约定好,其中 client 给server发送一个整形数字, 每个整形数字代表的操作不同. 发送1,代表注册; 2代表登录; 3代表访问数据...
不同的层的协议不同, 总的来说, 计算机之间的协议就是提前约定好数据的格式, 数据的各个部分都代表什么意思, 通信时直接根据协议的约定来解释即可. (具体的协议后面再说)
网络协议
为了能够传递各种不同的信息,通信的双方需要提前约定好数据格式,也就是协议。
只要通信的两台主机, 约定好通信协议就可以了么?
计算机之间的传输媒介 可以是光信号或电信号 ,本质上是一串0 和 1 的信号序列 。不同存储和传输介质对信号的感知方式 不同,通常通过**"频率""强弱""有无""正负"**等特性,来表示 0 和 1 的状态。
事实上,计算机生产厂商 有很多,操作系统 种类繁多,网络硬件设备 的类型也各式各样。虽然这些设备都可以遵循相同的通信协议 ,但由于它们的电气特性 (如电平、频率、传输介质等)不同,仅仅将它们硬件接入互联网并不能保证互联互通。因为互联网必须能够让不同的主机在不改变自身设备的基础上无障碍地通信。
要解决这个问题, 就需要制定一个共同的标准, 让所有厂商都遵守, 这就是网络协议的由来.
网络协议的设计目标是使不同厂商的硬件和软件能够实现无缝通信,而**并不要求完全统一硬件的电气特性.**相反, 协议的制定者会考虑这些差异, 为它们定义统一的规则.
- 物理层, 标准会规定信号的电压范围、脉冲形态或传输介质(如铜线、光纤、射频信号).硬件厂商可以自由设计电器特性, 只需保证其产品在传输和接收时符合公共协议标准(如以太网的物理层标准 IEEE 802.3).
- 更高层的协议(如 TCP/IP)屏蔽了底层硬件的差异, 为应用层提供统一的通信接口.
通过这种分层设计, 网络协议既能适应不同设备的硬件特性, 也能保证全球范围内的互联互通.
此外, 网络协议的演化是一个持续优化的过程,各个组织最开始都有不同的硬件和软件协议. 而目前的协议标准也不是"绝对最优"的,而是出于兼容性和实用性考虑的折衷。比如 TCP/IP 协议并非效率最高的传输协议,但它是互联网的基础,因为它具备良好的扩展性和适应性。
网络与系统
1. 网络通信的问题
一台主机发送数据到另一台主机, 虽然逻辑上我们只认为是两个主机之间的通信.但由于通信的距离变长, 实际物理上是需要经过很多转发(跳)的.
a. 如何保证数据先交给下一跳的主机?
b. 在转发中, 如何进行路径选择, 也就是目标主机定位问题(交给哪一个主机)?
c. 如果报文中出现 错误 或者 丢失, 如何处理?
解决了abc三个问题已经能保证A主机把数据可靠的送给B主机, 但是:
d. 送达的数据, 我们如何使用呢?
为了解决abcd的每一个问题, 都要有协议去解决. 因此计算机网络中的协议是非常多的 . 所以为了更好的解决协议管理的问题, 网络采取分层结构.
2. 网络协议的解决方案---网络的层状结构
**计算机领域的名言之一:**计算机科学中的任何问题都可以通过增加一个间接的中间层来解决" - 大卫·帕特森(David Patterson)
实际上, 软件中的绝大部分的解决方案都是层状的. 比如以打电话为例:
A和C 两个人通过座机打电话,当电话打通时:
对于A和C来说,他们都认为自己在直接与对方通话; 对于两台电话机来说. 它们也认为是它们之间在互相传递信息. 这样一来, 整个通话的信息传递就分为了两层:语言层 和 通信设备层
两层每层都有各自的协议:
语言层, A和C使用特定的语言 交流.
通信设备层, A的电话机和C的电话机使用电话机协议交流.
- 如果A和C使用英语交流,只是语言层的协议从汉语变成了英语, 电话机协议不需要改变. 两人同样可以正常通话
- 如果A和C使用无线电来通话, 此时仅是通信设备层的协议从电话机协议变成了无线电协议, 语言层仍然使用汉语协议.
分层的优点:
各层之间是独立的. 某一层并不需要知道它的下一层是如何实现的, 而仅仅需要知道该层通过层间的接口(即界面)所提供的服务。由于每一层只实现一种相对独立的功能, 因而可将一个难以处理的复杂问题分解为若干个较容易处理的更小一些的问题。这样, 整个问题的复杂程度 就下降了。
灵活性好. 当任何一层发生变化时(例如由于技术的变化), 只要层间接口关系 保持不变, 则在这层以上或以下各层均不受影响。此外, 对某一层提供的服务还可进行修改。
当某层提供的服务不再需要时,甚至可以将这层取消。
结构上可分割开. 各层都可以采用最合适的技术来实现。
易于实现和维护. 这种结构使得实现和调试一个庞大而又复杂的系统 变得易于处理 ,因为整个的系统已被分解为若干个相对独立的子系统 .
能促进标准化工作. 因为每一层的功能及其所提供的服务都已有了精确的说明
总的来说, 分层最大的好处是: 完成了软件的解耦合,
- 低耦合, 某一层发生变化并不影响其他层
- 高内聚, 功能比较集中, 耦合度比较高的模块都会分在同一层
未来非常方便对软件进行维护, 因为对每一层的维护(更新, 替换, 优化等)都不会影响其它层.
OSI七层模型
OSI(Open System Interconnection, 开放系统互连)七层网络模型称为开放式系统互联参考 模型, 是一个逻辑上的定义和规范;
OSI把网络从逻辑上分为了7层. 每一层都有相对应的物理设备, 比如路由器, 交换机;
OSI 七层模型是一种框架性的设计方法, 其最主要的功能使就是帮助不同类型的主机实现数据传输;它的最大优点是将服务、接口和协议这三个概念明确地区分开来, 概念清楚, 理论也比较完整. 通过七个层次化的结构模型使不同的系统不同的网络之间实现可靠的通讯.
TCP/IP五层模型
虽然OSI模型很完善, 但是实际发现应用层的三层并不适合分层, 所以工程中 我们一般按照TCP/IP的五层模型来使用:
物理层: 负责光/电信号的传递方式. 比如现在以太网通用的网线 (双绞线)、早期以太网采用的电话线, 同轴电缆 (现在主要用于有线电视)、**光纤.**现在的 wifi 无线网使用电磁波等都属于物理层的概念. 物理层的能力决定了最大传输速率、传输距离、抗干扰性等.
其中集线器(Hub)工作在物理层.
集线器是加强信号 的机器. 如果我们需要把一条信息从A城市送到B城市, 数据需要长距离传输 。而信息必须使用一定的物理介质传播. 在传递过程中信息的强度就会逐步减弱, 当信号将要衰减至无法识别前, 集线器就会将该信号加强, 以达到远距离传输的目的
数据链路层: 负责设备之间的数据帧的传送和识别 . 例如网卡设备的驱动 、帧同步 (就是说从网线上检测到什么信号算作新帧的开始)、冲突检测 (如果检测到冲突就自动重发)、数据差错校验等工作. 有以太网、令牌环网, 无线LAN等标准.
其中: 交换机(Switch)工作在数据链路层, 负责将数据传输到与该设备直接相连的下一台主机
网络层: 负责地址管理和路由选择. 例如在IP协议中, 通过IP地址来标识一台主机, 并通过路由表的方式规划出两台主机之间的数据传输的线路(路由).
其中: 路由器(Router)工作在网路层.
传输层: 负责两台主机之间的数据传输. 如传输控制协议 (TCP), 能够确保数据可靠的从源主机发送到目标主机.
应用层: 负责应用程序间沟通,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等. 网络编程主要就是针对应用层
所以我们之前的abcd问题可以在每一层分别单独解决:
3. 网络与系统
网络协议栈和操作系统的关系非常密切:
TCP/IP协议栈之所以以TCP/IP命名, 因为他们是在操作系统内核中实现的.
网络协议是标准规定的, 对于不同的操作系统, 我们不敢说他们左侧操作系统的实现是一样的, 但是网络协议为了保证全网主机都能无障碍接入网络, 不管我们使用的是Windows、Linux还是MacOS, 它们**对于网络协议栈的实现就应该完全一样,**否则无法通信.
我们在网络上下载, 看视频, 聊天时, 系统中一定会收到非常多的报文 , 操作系统需要管理这些已经收到的报文, 管理的方式 就是创建一个描述 该报文的结构体, 通过特定数据结构组织 起来, 最后对报文的管理变为对数据结构的增删查改.
局域网络通信
局域网关注的是如何将小范围的多台计算机互联起来. 比如学校的实验室, 通过交换机或无线小路由, 将实验室的所有电脑组成一个内部网络, 再连入校园网中.
1. 重谈协议
正如我们收快递一样, 我们不是只收到快递物品本身, 还会收到一份快递单. 所以实际上: 快递单 本身是一种协议 , 长距离发送时, 快递 = 快递单+内容.
在网络通信中, 快递称为报文 , 快递单是报头 , 快递内容是通信的内容.
协议 通常是结构化字段 表征的, 这个结构化字段所定义的对象, 就成为协议报头.
cpp
truct tcphdr {
__be16 source;
__be16 dest;
__be32 seq;
__be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
__be16 window;
__sum16 check;
__be16 urg_ptr;
};
TCP/IP协议栈的工作原理
首先我们要清楚, TCP/IP协议栈的每一层都具有一定的功能, 上层通过接口可以使用本层提供的功能, 这种功能的子集称作服务.
- 交换数据: 每一层的PDU通过使用下层的服务传送给**对方对等层,**服务是垂直关系
- 对等层的实体通过协议来交换信息, 协议是交换信息所遵守的规则的集合, 协议是水平关系
因此服务于协议的关系:
本层协议的实现要靠下层提供的服务来实现
本层实体通过协议为上层提供更高级的服务
但是对用户来说, 我们不关心数据是如何一层层传递下去, 又一层层传递上来. 我们一直都认为是主机A的应用进程直接 把数据交给了主机B的应用进程.因此在逻辑上每一层 都认为对等层之间的通信是数据通过水平虚线直接传递给对方, 水平方向上利用协议进行的对等层通信.
但是在系统的角度而言, 实际上数据交换的过程是 按垂直方向进行的, 最终 在物理层传递真实的数据 , 因此数据就一定需要贯穿协议栈, 自上而下地逐个通过每一层, 直到被当做一串比特流经过物理层送入网络.
而贯穿协议栈的过程就涉及到封装与解包.
封装: 数据从协议栈的上层向下层不断添加报头的过程
解包: 各层协议利用报文首部所携带的协议控制信息做相应的处理, 然后去掉各层协议数据单元的首部, 将封装的数据交给上层协议. 每层协议都要检查协议首部中的协议标识, 以确定让哪一个协议接收数据.
总而言之, 发送数据时需要自上而下, 层层封装. 接收数据时需要自下而上, 层层拆封.
协议数据单元
协议数据单元(PDU)是对等层的实体之间交换数据的基本单元. 在TCP/IP模型中, 各层的PDU名称:
- 应用层: 请求回复报文(request&response)
- 传输层: 段(Segment)
- 网络层: 分组(Packet)
- 数据链路层: 帧(Frame)
- 物理层: 比特流(bit)
封装和解包的思考
对于人来说, 我们考虑穿衣服, 就要考虑怎么脱衣服. 对于封装来说, 我们一定要考虑后面解包的过程.
所以当我们谈论应用层往下的所有协议时, 我们都要考虑两个问题:
封装时, 如何将报文中的**报头和有效载荷进行分离,**比如定长报头, 提前约定好报头的长度.
任何协议, 都要考虑如何将自己的有效载荷, 交付给上一层的指定协议. (比如MAC帧中携带了上层的协议类型)
这是每个协议设计的共性, 下面我们会看到MAC帧的设计就体现了这两个问题.
局域网的协议
局部网的协议主要对应于参考模型中的物理层和数据链路层.IEEE 802标准将局域网的数据链路层分为两个子层: LCC(逻辑链路控制)和MAC(媒体访问控制)
IEEE 802 委员会关于局域网,城域网的部分标准:
2. 局域网中, 多台主机能直接通信吗? 如何通信?
MAC地址
在同一个局域网内, 两台主机可以直接通信 . 为了明白如何实现计算机之间的一对一的通信, 我们需要每一个计算机都有一个和其它计算机不一样的地址, 以太网采用的地址是: MAC地址.
同身份证一样, 每个网卡也需要一个可以唯一标识自己 的名字, 这个名字就是MAC地址 . 在局域网中**每台电脑的MAC地址是唯一的.**每个MAC地址大小为6个字节, 48个比特位.
MAC地址在网卡出厂时就已经确定, 不能修改, 通常是唯一的. (虚拟机中的mac地址不是真实的mac地址, 可能会冲突)
1. Linux下,ifconfig指令可以查看Linux机器的网络信息: 其中属性ether(以太) 的内容是MAC地址.
- Windows下**, ipconfig /all**也可以查看MAC地址.
MAC帧的格式有两种, 以DIX第二版本的MAC帧为例:
数据部分就是网络层封装下来的IP数据报(快递本身), 而其它部分就是帧的报头. MAC帧总长度是64字节.
- 目的地址表示目的主机的MAC地址, 源地址表示本主机的MAC地址
- 类型表示这个帧上一层使用的是什么协议, 以便于解封装时把数据交给正确的上一层的对应协议中(最常见是0x0800, 指IP协议)
- 数据部分是要传递的数据本身了, 长度小于46字节需要填充至46字节, 高于MTU(比如1500字节)时, 需要分片传输, 这属于网络层的部分
- FCS是帧校验序列, 比如CRC(循环冗余码)
MAC帧前还有7字节的前同步码和1字节的帧开始界定符, 了解即可.
前同步码: 用来使接收端的适配器在接收 MAC 帧时能够迅速调整时钟频率,使它和发送端的频率相同
帧开始标志符: 为 1 个字节。前 6 位 1 和 0 交替,最后的两个连续的 1 表示告诉接收端适配器:"帧信息要来了,准备接收"。
局域网的媒体访问控制方法
实际上局域网的通信准则有很多, 最常见的就是以太网、令牌环网 和 无线局域网.
令牌环网
令牌环网 是基于轮询 的媒体访问控制方法, 它在物理上可能是总线型和环形, 但是在逻辑上时环形的. 在某一个时刻, 局域网中只有一台主机想要发送数据必须要拥有令牌, 整个网络只有一个令牌, 所以某一时刻只有一个站点在发送数据 . 所以它实现了一种无冲突的信道访问.
无线局域网(WLAN)
无线局域网主要分为有固定基础设施 的无线局域网 和无固定基础设施的无线局域网. 采用的协议是CSMA/CA协议, 而非以太网中的CSMA/CD协议. 具体暂不展开.
以太网
这里主要介绍以太网 , 以太网是以基于随机访问 的媒体访问控制方法, 以太网不像令牌传递的网络, 信道并不是固定的分配给某个用户, 所有用户可以随机的向信道发送信息, 也都可以接受到信息, 但是用户在发送数据时会产生冲突!
以太网中每台主机只会接收信道中"发往本站的帧", 包括单播帧, 广播帧, 多播帧. 这里我们以单播为例(一对一), 广播和组播(一对多)只是接收帧的主机数变多.
如果把教室看作局域网, 教室内每个人都看作一台计算机. 那么每个人彼此之间都能相互通信. 老师与学生, 学生与学生之间都可以相互通信.
- 但是当老师(源MAC)指明喊出小明(目的MAC), 你过来一下 . 这句话其实班级内的所有人都听到了 , 但是因为老师叫的是小明, 所以只有小明做出了反应. 小红、小刚等其他人知道老师叫的不是自己, 就直接将信息(报文)丢弃忽略了.
以太网物理上可能是总线的, 星形的(集线器汇聚) , 但是在逻辑上是总线形式 的, 现在所有的主机都接入了同一个局域网, 所以每一个主机都可以与局域网内的其他主机进行通信. 如果此时源主机发送了一条信息, 但是只有目的主机会处理该数据, 其他主机虽然也能接收数据, 但是会丢弃掉.
以太网的工作原理
- 由于教室是每个人的公共场所, 每个人都可能在任何时间开始发送信息, 空气就是此时唯一的信道, 那么当多组同学一起开始说话时, 我们必然都接收到了嘈杂的噪音, 此时的数据产生了冲突!
基于随机访问媒体控制的以太网也一样, 用户有数据就可以发送, 但是也可能在这个唯一的信道中产生冲突 . 由于广播信道 具有反馈性 , 我们可以在发送数据时进行冲突检测, 将反馈接收的数据与自己缓冲区的数据做比较, 就可以检测冲突.
如何协调多台计算机对总线传输媒体的访问控制问题(冲突问题)?
基于随机访问的媒体访问控制最开始采用ALOHA 和 时隙ALOHA 协议, 在此基础上延伸出了CSMA协议, 其中包括: 1-持续CSMA, 非持续CSMA和 p-持续CSMA, 其中以太网使用的CSMA/CD(多点接入载波监听冲突检测)协议是采用了1-持续CSMA协议.
CSMA/CD包含三个方面:
- 多点接入: 在总线式的局域网中, 有多台计算机连在一根总线上, 共享总线的信道资源.
- 载波监听: 每个计算机在发送数据前, 要监听信道是否空闲, 如果有计算机在发送数据则等待;如果没有, 就发送.
- 冲突检测: 正在发生数据的计算机在整个数据发送过程中, 必须监听传输媒体是否发生了冲突 . 因为载波监听得到的**"空闲"并不一定是真正意义的空闲** , 还可能是其它计算机发送的信号还没到达本计算机的网络接口上 , 所以一旦检测到冲突, 发送方立即停止发送, 并等待一个随机的时间间隔后重新发送.
征用期
一个站点开始发送数据后, 最多经过时间 2τ(端到端的往返时延)就可知道是否发生了碰撞, 2τ 称为征用期 , 也叫冲突窗口.
在0~2τ的时间内, 都可能会发生冲突. 因为保证AB双方都检测到碰撞, 最少需要2τ.所以 如果经过争用期2τ还没有检测到碰撞, 就可以肯定这次发送不会发生碰撞.
最短帧长
在10MB/s的局域网, 征用期长度为51.2us, 所以最短帧长Lmin = 2τ*C = 512bit(64字节).
为什么最短帧的大小取决于争用期时长?
因为如果最短帧的传输时间小于争用期2τ, 那么就会导致发送完这个帧之后, 在不知道帧有没有传送成功的情况下, 还能发送了下一个帧.
二进制指数退避算法
如果检测到冲突, 我们需要等待一个随机的时间, 再进行下一次传送. 以太网使用了二进制指数退避算法这样的技术. 暂不展开.
在操作系统的角度看局域网
谈了这么多, 从操作系统的角度来看, 我们能发现:
1. 局域网是一个临界资源
2. 对数据进行冲突检测/避免, 重传 的行为实际上是在进行对临界资源的互斥访问!
网络中的地址管理
我们在以太网中已经了解过MAC地址, 还有一种地址是IP地址.
什么是IP地址?
IP地址是在IP协议中, 用来表示互联网(或局域网)中唯一的一台主机; 其中IP协议有两个版本,IPv4和IPv6. 我们一般提到IP协议时, 默认都是指IPv4
对于IPv4来说, IP地址是一个4字节, 32位的整数, 我们通常也使用 "点分十进制" 的字符串表示IP地址,格式: [0-255].[0-255].[0-255].[0-255] ,例如 192.168.0.1.
在网络传输中, IP地址用4字节传输即可, 但是相比32位二进制数, 我们更愿意看到点分十进制的字符串表示, 因此可以设计一个ip_struct便于转换.
cpp
struct ip_struct
{
uint8_t p1;
uint8_t p2;
uint8_t p3;
uint8_t p4;
};
//初始化一个具体的ip地址
ip_struct ip;
ip.p1 = ;
ip.p2 = ;
ip.p3 = ;
ip.p4 = ;
//当我们传输ip地址时
uint32_t* ipAddr = (uint32_t)&ip;
//当我们转换为字符串时
uint8_t num1 = (uint8_t)&ip->p1;
uint8_t num2 = (uint8_t)&ip->p2;
uint8_t num3 = (uint8_t)&ip->p3;
uint8_t num4 = (uint8_t)&ip->p4;
然后进行字符串拼接即可...
IP vs MAC
既然MAC和IP都用于标识唯一的一台主机, 那么它们有什么区别和联系?
抽象地来描述, (源和目的)IP地址是一对终极目标 , 是一直不变的; 而(目的和源)MAC地址是阶段性的目标, 是时刻发生变化的.
举个例子:
1. 假设网络上要将一个数据包由 主机A(IP地址为IP_A, MAC地址为MAC_A) 发送到 主机B(IP地址为IP_B, MAC地址为MAC_B) 这两台主机之间不在同一个局域网内, 因而数据包在传递时必然要经过许多路由设备, 我们假定在传输过程中只经过一个路由器.
- 到达网络层时, 先发送一个ARP请求, 找到其要到达 IP_B 所必须经历的第一个中间节点路由器C的MAC地址MAC_C, 然后在IP数据报头中**封装源MAC和目的MAC:(MAC_A和MAC_C),**然后经过网卡通过以太网传给路由器的网卡, 通过以太网驱动程序解包得到对应的IP数据报:
- 当报文传到C后, 再查路由表发现IP地址为IP_B的B主机恰好与C直接相连, 于是**重新封装源MAC和目的MAC: (MAC_C,**MAC_B), 最终传送给主机B.
我们可以发现: 在传输过程中, 源IP和目的IP一直不变, 而MAC地址在不断改变.
IP地址的关键意义在于路径的选择, 就像坐地铁一样, 我们去往的目的地不同, 我们所经过的车站是不一定相同的. 同理, 根据不同的IP地址, 我们选择的路由器也是不同的, 从而走过的路径是不同的.
跨网络通信的过程大致如下图 :