Skip to content

网络

OSI(Open System Interconnection)是理想化的模型,将网络进行分层(也就是将网络通信的过程分为七个层级),其目的是将复杂的流程简单化,从而实现分而治之

参考文章

1 OSI 七层模型(描述整个网络的)

  • 七层是理想化的模型,将复杂的网络进行划分(实现的时候不用七层型,4,5 层)
  • 对于整个网络的通信过程来进行分层,目的就是让复杂的东西简单化。分而治之

1.1 物数网传会表应

  • 应用层(用户最终使用的接口)

  • 表示层(表示数据的格式,数据的编码,压缩,加密)

  • 会话层(建立会话,管理会话,结束) > http 报文

  • 传输层(将数据传输到对方,中间数据丢失,网络不可靠。。。分段,有序) > 门牌号(端口号) > 数据段

  • 网络层(路由选择,寻址,选择那条线路) > 地址(ip 地址) > 数据包 > 逻辑地址

  • 数据链路层(将两个设备连接在一起,传输数据) > mac 地址 > 数据帧 > 物理地址

  • 物理层(目的就是传输 bit 流)> 物理设备 (光纤,同轴电缆)

下为了上而服务

node

1.2 网络分层的含义?

下层是为了上层提供服务的。

  • 物理层:(核心是传输数据比特流,将数据从一个节点传输到另一个节点),不关心具体的物理层:传输媒体(双绞线、光纤、同轴电缆、无线..)
  • 数据链路层: (主要关心两个设备之间传递数据),建立逻辑链接,将数据组合成数据帧进行传递(差错校测,可靠传输)
  • 网络层:(主要是进行路由选择和流量控制)进行逻辑寻址,定位到对方,找到最短的路径,进行数据包的传递
  • 传输层:(主要是对数据进行分段和重组及数据完整性保障)网络层不可靠,保证可靠的传输
  • 会话层:(负责建立、管理和结束会话)建立和管理会话的
  • 表示层:(负责将数据进行编码、压缩和解码)数据的表示、安全、压缩
  • 应用层: 用户最终使用的接口

1.3 应用举例

举例:写给女朋友信的过程

  • 1.应用层: 你心里有很多想对女朋友说的话。这个就是应用层中的数据
  • 2.表示层: 将你想说的话进行整合,有调理的表示出来
  • 3.会话层: 我希望我的信只能我的女朋看到别人不行(非女朋友偷看者死)
  • 以上这三个就是我们完整信的内容。
  • 4.传输层: 我自己不好意思亲手交给她,找个快递来。告诉他我家 504 她家 301,你发吧~
  • 5.网络层: 快递说这不是开玩笑吗? 你得给我个能找到他的地址 xxx 省 xxx 市 xxx 街道 xxx 小区。还得添上你的地址,原地址和目标地址。
  • 6.数据链路层: 信件到了快递总部,会进行分类增加标识,快递需要中转,先找到第一个中转站发过去,之后根据目的地地址依次进行中转发送。
  • 7.物理层:通过飞机、卡车将信邮寄到过去。

信件邮寄到目的地后,邮局会分配到对应的小区,找到对应的门牌号,我的女朋友就会拿到对应的信件了。

1.4 分层

一般情况下我们在通信过程中使用的是 TCP/Ip 协议簇,将此模型简化为四层模

  • 网络接口层(物理层,数据链路层)
  • 网络层
  • 传输层
  • 应用层(会话层,表示层,应用层)

node

1.5 七层协议

  • 报文:应用层 + 数据
  • 数据段:传输层 + 数据 + 端口号
  • 数据包:网络层 + 数据 + 端口 + IP 地址
  • 数据帧:链路层 + 数据 + 端口 + IP 地址 + MAC 地址

2 地址

2.1 IP 地址

  • ipv4:IP 地址的第四个版本,地址由 32 位二进制数值组成 例如:192.168.1.1,最大值:42 亿个(255 的四次方)
    • 255:255:255:255
  • IPv6 由 8 个 16 进制组成, 一共 128 位,终极2^128
    • 2408:8207:788b:2370:9530:b5e7:9c53:87 大约(2^128 = 3.4 * 10^38

IP 地址不是固定的(因为连接的网络不同),但是我们的 MAC 地址是唯一的(也是可以更改的),每个网卡都会有一个固定的 MAC 地址。

2.2 MAC 地址

设备通信都是由内部的网卡设备来进行的,每个网卡都有自己的 mac 地址(原则上唯一)

3 每层物理设备

  • 物理层 线路(光纤)
    • 中继器 (简单的连接两个设备,这一层就可以做到)网线最大传输距离 100m。只能连接两个设备
    • 集线器 可以实现多个设备的互联,多口的中继器,通信的时候 是“广播”的形式
  • 数据链路层
    • 交换机(第一次是广播的形式找到对方,后面可以直接和对方联系)飞秋,无法做到网络连接
  • 网络层,
    • 路由器 只有 lan 口 的路由器可以理解成交换机, wan 口后可以做到连接互联网的功能(网关) 让两个子域通信
    • 网关: 两个子网之间不可以直接通信,需要通过网关进行转发

网址简化了 ip,ip 简化了 mac 地址,在访问过程中 ip 地址是不会变化的,变化的是 mac 地址

node

4 TCP/IP 参考模型

Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议。TCP/IP 协议实际上是一系列网络通信协议的统称,最核心的两个协议是 Icp 和 IP

4.1 什么是协议?

协议就是约定和规范

4.2 每层的“协议”

数据链路层、物理层都属于物理设备。

在七层模型中只有三层以上的才能称之为协议。常见的协议有:

  • 网络层:
    • IP 协议:寻址通过路由器查找,将消息发送给对方路由器,通过 ARP 协议,发送自己的 mac 地址
    • ARP 协议:Address Resolution Protocol 从 ip 地址获取 mae 地址(局域网)。
  • 传输层:
    • TCP
    • UDP
  • 应用层:
    • HTTP
    • DNS:因为用户很难记住 IP 地址,所以出现了 DNS
    • DHCP:自动获取网络配置信息(动态主机配置协议),自动分配 IP,基于 UDP。
    • FTP
    • TFTP
    • SMTP

4.3 ARP 协议

根据目的 I 地址,解析目的 mac 地址

node

ARP缓存表交换机MAC地址表
Internet 地址物理地址端口号物理地址
192.168.1.2B1A
2B
3C

有了源 mac 地址和目标 mac 地址,就可以传输数据包了。

4.4 DHCP 协议

通过 DHcP 自动获取网络配置信息(动态主机配置协议 Dynamic Host Configuration Protocol)我们无需自己手动配置 IP

4.5 DNS 协议

DNS 是 Domain Name System 的缩写,DNS 服务器进行域名和与之对应的 p 地址转换的服务器

  • 顶级域名.com、
  • 二级域名.com.cn
  • 三级域名 www.xxx.com.cn,有多少个点就是几级域名

访问过程:我们访问 xxx.com.cn

  • 操作系统里会对 DNS 解析结果做缓存,如果缓存中有直接返回 IP 地址
  • 查找 C:\WINDOWS\system32\drivers\etc\hosts 如果有直接返回 Ip 地址
  • 通过 DNS 服务器查找离自己最近的根服务器,通过根服务器找到.cn 服务器,将 ip 返回给 DNS 服务器
  • DNS 服务器会继续像此 ip 发送请求,去查找对应.cn 下.com 对应的 ip…
  • 获取最终的 ip 地址。缓存到 DNS 服务器上

node

查找过程就是一个递归的过程。

DNS 服务器会对 ip 及域名进行缓存,采用的是 UDP (无连接)

5 UDP

5.1 UDP 概念

udp用户数据报协议User Datagram Protocol,是一个无连接、不保证可靠性的传输层协议。你让我发什么就发什么!

  • 使用场景:DHCP 协议、DNS 协议、QUIC 协议等(处理速度快,可以丢包的情况)

node

5.2 UDP 抓包

client.js

js
const dgram = require("dgram");

const socket = dgram.createSocket("udp4"); // 双工流
socket.on("message", function (msg, rinfo) {
  console.log(msg.toString());
  console.log(rinfo);
});
socket.send(
  Buffer.from("helloworld"),
  0,
  5,
  41234,
  "localhost",
  function (err, bytes) {
    console.log("发送了个%d字节", bytes);
  }
);
socket.on("error", function (err) {
  console.error(err);
});

server.js

js
const dgram = require("dgram"); // udp模块

const socket = dgram.createSocket("udp4");
socket.on("message", function (msg, rinfo) {
  console.log(msg.toString());
  console.log(rinfo);
  socket.send(msg, 0, msg.length, rinfo.port, rinfo.address);
});
socket.bind(41234, "localhost");

udp.dstport = 41234

TIP

  • UDP 发出请求后,不考虑对方是否能接收到、内容是否完整、顺序是否正确。收到数据后也不会进行通知。
  • 首部结构简单,在数据传输时能实现最小的开销

6、TCP

两个协议都在传输层,我们经常说 TCP 是面向连接的,而 UDP 是面向无连接的。

6.1 TCP 概念

TCP 传输控制协议(Transmission Control Protocol)是可靠、面向连接的协议,传输效率低(在不可靠的 IP 层上建立可靠的传输层)。TCP 提供全双工服务,即数据可在同一时间双向传播。

6.2 TCP 数据格式

node

  • 源端口号、目标端口号,指代的是发送方随机端口,目标端对应的端口
  • 序列号:32 位序列号是用于对数据包进行标记,方便重组
  • 确认序列号:期望发送方下一个发送的数据的编号
  • 4 位首部长度:单位是字节,4 位最大能表示 15,所以头部长度最大为 60
  • URG:紧急信号、ACK:确认信号、PSH:应该从 TCP 缓冲区读走数据、RST:断开重新连接、SYN:建立连接、FIN:表示要断开
  • 窗口大小: 当网络通畅时将这个窗口值变大加快传输速度,当网络不稳定时减少这个值。在 TCP 中起到流量控制作用。
  • 校验和:用来做差错控制,看传输的报文段是否损坏
  • 紧急指针:用来发送紧急数据使用

TCP 对数据进行分段打包传输,对每个数据包编号控制顺序,

6.3 TCP 抓包

client.js

js
const net = require("net"); // tcp

const socket = new net.Socket(); // 双工流,套接字
// 连接8080端口
socket.connect(8080, "localhost");
// 连接成功后给服务端发送消息
socket.on("connect", function (data) {
  // 浏览器给服务端说 hello --- 可写流
  socket.write("hello");
  socket.end();
});
// 可读流,读取服务端传递的消息
socket.on("data", function (data) {
  console.log(data.toString());
});
socket.on("error", function (error) {
  console.log(error);
});

server.js

js
const net = require("net");

const server = net.createServer(function (socket) {
  // 监听客户端的消息
  socket.on("data", function (data) {
    // 服务端给客户端说 hi
    socket.write("hi");
  });
  // 监听客户端的end事件
  socket.on("end", function () {
    console.log("客户端关闭");
    // 服务端给客户端说 hi
    socket.write("hi");
  });
});
server.on("error", function (err) {
  console.log(err);
});
// 监听8080端口
server.listen(8080);

抓包工具:Wireshark

6.4 TCP 三次握手,四次断开

6.4.1 建立连接

node

三次握手

  • 1)客户端:我能主动给你打·电话吗?

  • 2)服务端:当然可以啊!那我也能给你打电话吗?

  • 3)客户端:可以的呢,建立连接成功!

  • 第一次握手:在建立 TCP 连接时,客户机 A 向服务器 B 发出连接请求报文,其中同步位 SYN=1,同时选择一个初始序号 Seq=0,这时候客户机 A 进入 SYN-SENT(同步已发送)状态,

  • 第二次握手:服务器 B 收到报文段后,如果同意建立连接,则向 A 发送确认,在确认报文段中应把 SYN 位和 ACK 为都置为 1,确认号 ACK=(Seq=0)+ 1 = 1,同时也为自己选择一个初始序列号 Seq=0,这时服务器 B 处于 SYN-RCVD(同步收到)状态,

  • 第三次握手:客户机 A 收到 B 的确认以后,还要给 B 给出确认,确认报文 ACK=1,确认号 ACK=(Seq=0)+ 1 = 1,自己的序号 Seq=1,这时 TCP 连接已经建立,A 进入 ESTABLISHED(已建立连接)状态,当 B 收到 A 的确认以后,也进入 ESTABLISHED 状态。

6.4.2 数据传输

node

6.4.3 断开连接

node

在客户端和服务端的连接需要断开的时候,需要一方发起断开的信号,然后双方开始进行应答交互,而因为服务端可能还有没有发送完的数据,所以会比握手多一次,最后完成断开。

握手和挥手时:ack = 对方的 seq + 1 个标致位 发送数据时:ack = 对方的 seq + 对方的 len

四次挥手

  • 1)我们分手吧

  • 2)收到分手的信息

  • 3)好吧,分就分吧

  • 4)行,那就到这里了

  • 客户端和服务端握手 seq = 0 ack = 0

  • 服务端到后, 会在你的序列号基础上 + 1 = ack (ack=1) , 并且用你的 ack 作为本次的 seq = 0

  • 客户端确认 ack = 1 seq = 1

用对方的 ack 作为本次的 seq (seq + 1 作为 ack)握手成功后

  • 客户端要给服务端发消息 ack = 1 seq = 1 len = 10
  • 服务端收到后, ack = seq + len = 11(收到了你发来的 10 个字节) (对方的 ack 就是我的 seq) seq = 1
  • 服务端在发消息 seq = 1 ack = 11 len = 10
  • 客户端收到了 ack = seq + len = 11 seq = 11
  • 客户端在发消息 ack = 11 seq = 11 len = 2
  • 对方收到了 ack = seq + len = 13 ack = seq = 11

断开就是相互+1

1.客户机 A 发送连接释放报文,并且停止发送数据,主动关闭 TCP 连接,A 把连接释放报文段首部的终止控制位 FIN=1 其序号 seq=u(等于前面已经传送过的数据的最后一个字节的序号加 1),这时候 A 进入 FIN-WAIT-1(终止等待 1)状态,等待 B 的确认,注意,TCP 规定,FIN 报文段即时不携带数据,他也会消耗掉一个序号。

2.服务器 B 收到连接释放报文,发出确认报文,确认号 ack=u+1,这个报文段自己的序号是 v,等于 B 前面已经传送过的数据的最后一个字节的序号加 1,然后 B 就进入了 CLOSED-WAIT(关闭等待)状态,TCP 服务器进程这时候通知高层应用进程,客户机 A 到服务器 B 这个方向的连接就释放了,这时 TCP 连接处于半关闭(half-close)状态,即 A 已经没有数据要发送的了,但是 B 若发送数据,A 仍然要接收,也就是说,从 B 到 A 这个方向的连接并没有关闭,这个状态可能会持续一段时间,

3.A 收到来自 B 的确认后,就进入 FIN-WAIT-2(终止等待 2)状态,等待 B 发出的连接释放报文段

4.若 B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接,这时 B 发出的连接释放报文段 FIN=1,ACK=1,假定 B 的序号 seq=w(在这半关闭状态 B 可能又发送一些数据),B 还要重复上次已经发送过的确认号 ack=u+1,这时 B 就进入 LAST-ACK(等待确认)状态,等待 A 的确认

5.A 在收到 B 的连接释放报文段后,必须对此发出确认,在确认报文中把 ACK=1,确认号 ack=w+1,自己的序号是 seq=u+1,然后进入 TIME-WAIT(时间等待)状态,注意此时 TCP 连接还没有释放掉,必须经过时间等待计时器(TIME-WAIT timer)设置的时间 2MSL 后,A 才能进入 CLOSED 状态

6.服务器 B 收到了 A 发出的确认,就会进入 CLOSED 状态,同样 B 在撤销相应的传输控制块 TCB 后,就结束了这次的 TCP 连接,我们注意到,B 结束 TCP 连接的时间比客户机 A 要早一点。

为了防止最终的 AC 丢失,发送 AcK 后需要等待一段时间,因为如果丢包服务端需要重新发送 FIN 包,如果客户端已 closed,那么服务端会将结果解析成错误。从而在高并发非长连接的场景下会有大量端口被占用。

6.5 滑动窗口

主要是用来控制流量的。缓存区的缓存被上层(HTTP 等)消费之后,就会把缓存释放掉。

  • 滑动窗口:TCP 是全双工的,所以发送端有发送缓存区;接收端有接收缓存区,会根据网络状况调整发送数据的多少。要发送的数据都放 到发送者的缓存区,发送窗口(要被发送的数据)就是要发送缓存中的哪一部分
  • 我们发送数据的时候是乱序发送的,但是当我们收到某个包后,可能之前的包还没有收到,此时需要等待前面序号的包到了才可以(队头阻塞)
  • 服务端和客户端会说明发送数据的个数
  • 如果某个数据包丢失了,就会重新发送(超时重传 RTO)
  • 核心是流量控制:在建立连接时,接收端会告诉发送端自己的窗口大小(rwnd),每次接收端收到数据后都会再次确认(rwna)大小,如果值为 0,停止发送数据。(并发送窗口探测包,持续监测窗口大小),实际上就是控制发送方的频率
  • 当接收方的缓存区满了,每隔一段时间,发送方都会发送一个探测包,来询问能否调整窗口大小。而当上层协议消耗掉接收放的数据,接收方也会主动通知发送方调整窗口,从而继续发送和接收数据

6.6 粘包

  • 每次发送一个数据,都会额外的增加一个 tcp 的 header,每次发送一个字节

  • 能不能把较小的包连接在一起

  • 默认采用 nagle 算法 ,保证只有一个小段正在发送,后续的就可以粘包,但是问题在于如果响应的很快,默认还没有粘包,还是一个个发送,可以采用 cork 算法来实现,粘包,达到最大值或者没有其他内容一并发送

  • Nagle 算法的基本定义是任意时刻,最多只能有一个未被确认的小段(TCP 内部控制)

  • Cork 算法当达到MSS(Maximum Segment Size )值时统一进行发送(此值就是帧的大小 - IP 头 - TCP 头 = 1460 字节)理论值

6.7 TCP 拥塞处理(队头阻塞)

注意:如果在非长链接的情况下会有大量端口被占用的问题。

举例:假设接收方窗口大小是无限的,接收到数据就能发送 ACK 包,那么传输数据主要是依赖于网络带宽,带宽的大小是有限的。

  • TCP 维护一个拥塞窗口 cwnd(congestion window)变量,在传输过程中没有拥塞就将此值增加。如果出现拥塞(超时重传 RTO(Retransmission Timeout))就将窗口值减少
  • cwnd < ssthresh 使用慢开始算法
  • cwnd > ssthresh 使用拥塞避免算法
  • RTO 时更新 ssthresh 值为当前窗口的一半,更新 cwnd = 1

node

  • 传输轮次:RTT (Round-trip time),从发送到确认信号的时间
  • cwnd 控制发送窗口的大小

node

快重传,可能在发送的过程中出现丢包的情况。此时不要立即回退到慢开始阶段,而是对已经收到的报文重复确认,如果确认次数达到 3 次,则立即进行重传快恢复算法(减少超时重传机制的出现和降低重置 cwnd 的频率)

7、HTTP

7.1 HTTP 发展历程

1990 年 HTTP/0.9 为了便于服务器和客户端处理,采用了“纯文本“格式,只运行使用 GET 请求,在响应请求之后会立即关闭连接。

1996 年 HTTP/1.0 增强了 0.9 版本,引入了 HTTP Header(头部)的概念,传输的数据不再仅限于文本,可以解析图片音乐等,增加了响应状态码和 PoST,HEAD 等请求方法。(内容协商)

1999 年广泛使用 HTTP/1.1,正式标准,允许持久连接,允许响应数据分块,增加了缓存管理和控制,增加了 PUT、DELETE 等新的方法。(问题 多个请求并发 http 队头阻塞的问题)

2015 年 HTTP/2,使用HPACK算法压缩头部,减少数据传输量。允许服务器主动向客户端推送数据,二进制协议可发起多个请求,使用时需要对请求加密通信

2018 年 HTTP/3 基于 UDP 的 QUIc 协议。

7.2 HTTP/1.1

  • HTTP/1.1 是可靠传输协议,基于 TCP/IP 协议;
  • 采用应答模式,客户端主动发起请求,服务器被动回复请求
  • HTTP 是无状态的每个请求都是互相独立
  • HTTP 协议的请求报文和响应报文的结构基本相同,由三部分组成。

7、请求方法

  • HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD 方法
  • HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法
方法描述
GET请求指定的页面信息,并返回实体主体
POST向指定资源提交数据请求,数据被包含在请求体中
HEAD类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
PUT向服务器发送数据,用于修改
DELETE请求服务器删除指定的资源
OPTIONS向服务器询问支持的方法,比如跨域
CONNECTHTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器
TRACE回显服务器收到的请求,主要用于测试或诊断
PATCH是对 PUT 方法的补充,用来对已知资源进行局部更新
  • get、post 为简单请求,其他都为复杂请求
  • 如果用户添加了自定义信息也算复杂请求
  • 跨域请求:options 预检请求 跨域时会携带
  • cookie 不允许跨域,预检不通过不会发送后续的内容了

四、状态码

HTTP 状态码

HTTP状态码

Released under the MIT License.