这里写目录标题
- [<font color="FF00FF">1. OSI七层模型](#1. OSI七层模型)
- [<font color="FF00FF">2.协议](#2.协议)
- [<font color="FF00FF">3. 网络](#3. 网络)
-
- [<font color="FF00FF">3.1 局域网(以太网为例,令牌环网和无限LAN类似)](#3.1 局域网(以太网为例,令牌环网和无限LAN类似))
- [<font color="FF00FF">3.2 跨网络传输](#3.2 跨网络传输)
1. OSI七层模型
ISO(国际标准化组织):为了让不同的计算机进行通信,ISO定义了一个OSI模型,OSI模型定义了网络通信的七层协议结构


会话层和表示层被合并到应用层,物理层是一些物理的概念,我们只关心四层:
- 网络层
- 数据链路层
- 传输层
- 应用层
为什么要有TCP/IP协议?
本质就是通信主机距离变远了会引发一些问题

这四个问题分别由下面这四层网络协议解决
- 网络层
- 数据链路层
- 传输层
- 应用层

所以实现网络协议栈的代码应该一样,操作系统是c写的,那别的平台也用c实现
2.协议
"协议"是⼀种约定
比如你和你的室友打电话,可以对电话铃响的次数进行约定
响一声:代表你不用接听去老地方吃饭
响两声:代表去打球
响三声:代表有事情需要你接听
有了这些约定减少通信成本
协议本质也是软件,在设计上为了更好的进行模块化,解耦合,也是被设计成为层状结构的

主机B能识别data,并且准确提取a=10,b=20,c=30吗?
能,因为双方都有同样的结构体类型struct protocol,也就是说用同样的代码实现协议,用同样的自定义数据类型,天然就能够识别对发来的数据,这就是约定
协议就是通信双方都认识的结构化的数据类型
因为协议栈是分层的,所以,每层都有双方约定的协议,同层之间,互相可以认识对方的协议
代码测试
c
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
// 定义一个结构体
struct Student {
int id;
char name[20];
float score;
};
int main() {
// 1. 定义并赋值一个结构体
struct Student stu_write = { 1001, "ZhangSan", 92.5 };
// ==================== 写入文件 ====================
FILE* fp = fopen("D:\\student.dat", "wb");
if (fp == NULL) {
perror("fopen failed");
return 1;
}
// 把整个结构体写入文件
fwrite(&stu_write, sizeof(struct Student), 1, fp);
fclose(fp);
// ==================== 从文件读回来 ====================
struct Student stu_read;
fp = fopen("D:\\student.dat", "rb");
if (fp == NULL) {
perror("fopen failed");
return 1;
}
// 整块读回结构体
fread(&stu_read, sizeof(struct Student), 1, fp);
fclose(fp);
// 打印验证
printf("id: %d\nname: %s\nscore: %.1f\n",
stu_read.id, stu_read.name, stu_read.score);
return 0;
}

这里验证了可以从文件里拿到结构体的所有属性和信息,网卡也是文件,所以能够做到从网卡里拿到结构体的所有属性和信息,但要注意要二进制的写入和读取,否则编译器不认识
3. 网络
- 每台主机在局域网上,要有唯一的标识用来标识全球范围内,主机的唯一性:mac地址
- MAC地址用来识别数据链路层中相连的节点
- 长度为 48 比特位,即 6 个字节,一般用16 进制数字加上冒号的形式来表示(例如:08:00:27:03:fb:19)
- 在网卡出厂时就确定了,不能修改,mac地址通常是唯一的内置在网卡里的
3.1 局域网(以太网为例,令牌环网和无限LAN类似)

- 以太网中,任何时刻,只允许一台机器向网络中发送数据
- 如果有多台同时发送,会发生数据干扰,我们称之为数据碰撞
- 没有交换机的情况下,⼀个以太网就是⼀个碰撞域
- 所有发送数据的主机要进行碰撞检测和碰撞避免
- 局域网通信的过程中,主机对收到的报文确认是否是发给自己的,是通过目标mac地址判定
- 其实以太网一个主机给另一个主机发送信息时,其它主机也可以收到,其中报头存储src和dst,检查报头后发现不是给自己的,数据链路层的时候直接舍弃该报文,上层不知道你丢弃了,所以才认为其它主机没收到信息
以太网是共享资源,主机是线程,
碰撞避免是锁,本质是一种算法,让其它主机休眠,只让一个主机访问以太网,保证互斥
这里其实是两个主机在数据链路层通信

但大多数情况数据都是人发送的,也就是说主机直接的通信本质是两个协议栈在通信,因为一个用户从自己的主机发送消息到另一个用户的主机上要贯穿整个协议栈,网络协议栈每一层都有协议

当用户A向用户B的主机发送你好时,要先到应用层,而应用层要把自己的应用层报头和要发送的信息(有效载荷)拼接,报头就是结构体,本质是二进制写入到文件的,里面描述着有效载荷的长度,然后依次向下封装,最后通过网卡发送给主机2的网卡,然后读取主机2的网卡,交给主机2的数据链路层,然后去掉报头,把有效载荷依次上传,用户就可以拿到你要发送的信息了,网卡也是文件
除去报头剩余的部分叫有效载荷,向下添加报头称为封装的过程,去掉报头的过程称为解包,向上传递自己的有效载荷称为分用
其中定义一个指针,然后强转成和报头一样的结构体类型,就可以拿到起始地址然后就可以访问结构体内的任意属性了,由于每个协议层的代码实现相同,并且由图可以看到每个协议层的报头和有效载荷是完全一样的,所以同层之间,都认为自己在和对方的同层协议在直接通信
- 为什么协议栈自顶向下封装?
必须贯穿操作系统,因为操作系统是网卡的管理者,也就是贯穿协议栈
在不考虑应用协议的前提下,任何协议
- 报头必须要能做到和有效载荷分离的能力
2.因为每个协议层有很多协议,所以报头中必须包含如何将自己的有效载荷交付给上层的哪个具体协议
其实以太网一个主机给另一个主机发送报文时,其它主机也可以收到,其中报头存储src和dst,检查报头后发现不是给自己的,数据链路层的时候直接舍弃该报文,上层不知道你丢弃了,所以才认为其它主机没收到报文
为什么叫协议栈?
- 因为每个协议层有很多协议,所以报头中必须包含如何将自己的有效载荷交付给上层的哪个具体协议->协议
- 因为封装的过程就是入栈的过程,分用的过程就是出栈的过程->出栈


其中把网卡改能混杂模式,它在数据链路层的时候就不丢弃报文了,所有报文都可以获取到,这就是抓包的原理
报文=报头+有效载荷
应用层的报文:请求与应答
传输层的报文:数据段
网络层的报文:数据报
数据链路层的报文:数据帧
3.2 跨网络传输
- IP 协议有两个版本,IPv4 和 IPv6
- IP 地址是在 IP 协议中,用来标识全球范围内,主机的唯一性(公网ip)
- 对于 IPv4 来说,IP 地址是⼀个 4 字节,32 位的整数
- 常用 "点分十进制" 的字符串表示IP地址,例如 192.168.0.1 用点分割的每一个数字表示一个字节,范围是0 - 255
- 数据从⼀台计算机到另⼀台计算机传输过程中要经过一个或多个路由器
这里的第二条好像跟mac一样啊?
其实是指向不同主机的,mac指向路由器,ip指向另一台主机,路由器也是主机

路由器是有两个驱动程序的也就是两个网卡,所以路由器就可以同时在两个局域网内

假设用户A的主机是主机A,用户B的主机是B,在一个局域网,也就是在一个子网中,它们的ip地址类似,假设都是192.168.2.x,而要发送给目标主机的ip地址是172.168.2.2,所以主机A虽然不知道172主机在哪,但是主机A一定能确定,报文绝对不是发给本地网络主机的,因为ip地址差距太大了,又因为路由器是和主机A在同一个局域网里,所以就可以判定要将此报文发给路由器,只要有网络层就有路由功能

从网络层到数据链路层时要封装mac帧,就是把自己网卡的地址macA,和要访问的路由器的网卡的地址macLeft封装成报头和有效载荷拼接,然后通过主机A的网卡传给路由器的网卡,再从网卡里读取报文到数据链路层,然后解包,并分用,此时src和dst就是路由器的网络层的报头了,有效载荷是你好,路由器在网络层读取报头发现你要访问的网络ip地址,是我右侧网卡连接的这个子网的,此时要路由,把网络层的报文向下封装,重新封装mac地址,就变成了如图哪个样子,然后继续传递,报文到主机B的数据链路层依次解包分用就可以让用户B拿到信息
由图可以发现从网络层开始向上就没有mac了,它屏蔽了底层局域网的不同,让上层只能看到ip地址,就跟struct file屏蔽了底层硬件的不同,实现一切皆文件的原理一样,所以网络层+ip的本质意义就是给网络提供了一层虚化层,让世界所有的网络都叫ip网络,也就是一切皆ip,都是ip地址,对struct file和系统也一样,
都是软件层(虚化层)
ip地址和mac地址的区别?
路由的过程中,ip地址一直不变,mac地址一直在变,mac地址只在本局域网的网络层以下有效
IP确定的是要通信哪台主机,mac确定的是要通信哪个路由器
多个路由器的场景
一切皆ip,那为什么不把局域网(mac地址)干掉,全换成ip网(ip地址)呢?
是能做到,但是没必要,因为本来ip就是网络层的概念,mac是数据链路层的概念,如果全换成ip,会使数据链路层和网络层强耦合,而网络是先局部通信再跨网络通信的,如果要换成ip网,世界所有的网卡和驱动全都要改,而且mac本来就没什么问题,所以为了兼容性不这么做
