计算机网络 | 青训营笔记

94 阅读11分钟

HTTP的建立

1. OSI七层模型与TCP/IP四层模型

OSI 七层模型OSI 五层模型TCP/IP四层模型
应用层应用层应用层
表示层--
会话层--
传输层传输层传输层
网络层网络层网络层
链路层链路层网络接口层
物理层物理层-

2. TCP握手协议(传输层、端对端)

2.1 建立链接

  1. 第一次握手

客户端主动打开链接,服务端被动打开。客户端发送SYN段(包含了客户端的初始序列号seq=i)

如果半连接队列未满,服务器将该链接的状态变为SYN_RCVD,并把链接信息放入半连接队列中。

否则,服务器不会将链接状态改为SYN_RCVD,并且丢弃该链接。

(SYN flood攻击,DDOS攻击的一种,就是借助这种方式,不断发送SYN段但是不处理SYN+ACK段,使服务器崩溃。应对方式之一是让syncookies=1,即使半连接队列已满也可以接受非恶意攻击的客户端请求。)

(SYN flood攻击的方式其实也分两种,第一种,攻击方的客户端一直发送SYN,对于服务器回应的SYN+ACK什么也不做,不回应ACK, 第二种,攻击方的客户端发送SYN时,将源IP改为一个虚假的IP, 然后服务器将SYN+ACK发送到虚假的IP, 这样当然永远也得不到ACK的回应。)

  1. 第二次握手

    服务端返回SYN+ACK段,且段中包含服务器的初始序列号seq=j,同时ACK=i+1,表示确认收到客户端的seq

    此时,客户端从SYN_SENT变为ESTABLISHED

  2. 第三次握手

    客户端返回ACK段,ACK=j+1,表示收到了服务器的初始序列号。

    服务器收到ACK后,如果全连接队列未满,服务器将该链接从SYN_RCVD变为ESTABLISHED,然后将该链接移出半连接队列,移入全连接队列。

    若已满,会根据tcp_abort_on_overflow的值进行执行相应步骤。

    1. 值为0

      给客户端定时(二进制指数退让)发送SYN+ACK重新进行第二次握手。

    2. 值为1

      重置连接(发送RST给客户端/忽略客户端传来的包,直到客户端认为异常断开)

2.2 断开链接

  1. 第一次

    主动关闭方发送FINseq=u,此时FIN只是意味着客户端不再发送数据,并不意味着他不再接收数据,客户端进入FIN_WAIT1状态。

  2. 第二次

    服务器给客户端发送FINACK= u+1,seq=v,表示收到了客户端的FIN,此时服务器进入CLOSE_WAIT状态,客户端收到ACK后,进入FIN_WAIT2状态。

  3. 第三次

    服务器确认发送完所有数据后,发送FINseq=wACK= u+1给客户端,之后进入LAST_ACK状态。

  4. 第四次

    客户端收到服务器的FIN后,发送ACK= w+1, seq= u+1

3. 状态码

  1. 1xx 信息性,代表请求已被接受,需要继续处理。

  2. 2xx 成功

    • 200 请求已成功
    • 201 表示资源已被新建
    • 204 成功但是不返回内容
  3. 3xx 重定向

    • 301 资源永久转移
    • 302 临时转移
    • 304 缓存未过期,可以直接使用
  4. 4xx 客户端错误

    • 400 语法错误,服务器无法理解
    • 401 身份认证错误
    • 403 无权限访问
    • 404 资源找不到
    • 409 资源冲突
  5. 5xx 服务端错误

    • 500 未知错误(服务器源代码、数据库错误)
    • 502 网关错误
    • 503 服务器超载或维护
    • 504 网关请求超时

HTTP版本差异

HTTP 1.0

1.0的HTTP是一个无连接、无状态的应用层协议。因此客户端每次请求服务器都需要建立一个TCP链接,服务器处理完TCP立即断开(无连接),服务器也不会记录每次的请求(无状态)。

无状态可以使用CookieSession来实现身份认证与状态记录(状态化)。

问题:

  • 无法实现连接复用

每次发送请求后,都需要进行一次TCP连接,TCP的连接与释放过程消耗很多资源,这种无连接特性会导致网络复用率变低。

  • 队头阻塞

由于HTTP 1.0规定下一个请求必须在前一个请求响应到达之前才能发送,假设前一个请求响应一直不到达,那么下一个请求将一直阻塞。

HTTP 1.1

长连接

HTTP 1.1解决了连接复用的问题。HTTP 1.1增加了Connection字段,通过设置Keep-Alive使得HTTP连接能够连接不断,避免客户端与服务器多次建立与释放TCP连接,提高了网络的复用率。

当客户端需要关闭连接的时候,可以在请求头的Connection设为false告知服务器关闭。

管道化

基于长连接实现,客户端能够发送多个请求,但是服务器必须按照请求的顺序依次回应相应的结果,即:让队列从客户端的请求队列迁移到了服务器的响应队列,但是仍然没有解决队头阻塞的问题。

缓存处理(强缓存、弱缓存、启发式缓存)

HTTP 2.0

二进制分帧

HTTP 2.0通过在应用层与传输层之间增加了一个二进制分帧层,突破了HTTP 1.0的性能限制,改进了传输性能。

多路复用

  • :已建立连接上的双向自己流。
  • 消息:与逻辑消息对应的完整的一系列数据帧。
  • 帧(frame) :HTTP 2.0通信的最小单位,每个帧包含头部,至少也会标识出当前所属的流(stream_id)

每个数据流以消息的形式发送,而消息由一个或者多个帧组成。帧可以乱序发送,然后依赖流标识符重新封装。

并且HTTP 2.0的数据流可以设置优先级依赖

头部压缩

在HTTP 1.X中,头部源数据都是以纯文本的形式发送的,会给每个请求头增加较多字节的负荷(Cookie),HTTP 2.0要求客户端与服务器都缓存一张Header_Files表,将Header进行编码压缩,避免了重复Header的传输,减小了传输的负荷。

服务器推送

即客户端发送一次请求,服务器会主动将所需要的资源一次性推送给客户端。eg: 客户端请求一个index.html资源,服务器将在一次请求内将所有所需的index.css, index.js等资源返回给客户。

这里的问题在于当用户误触到某个链接的时候,由于服务器推送机制,用户会一次性获取非常多不必要的资源,这种可能会造成DDoS攻击的实现。

HTTP 3.0

HTTP 2.0成功解决了头部阻塞的问题,但是这里解决的只是应用层的头部阻塞,在传输层的TCP中,出现丢包的情况整个TCP都要等待重传,即传输层的头部阻塞并没有被解决,而修改TCP协议是不可能的(TCP协议由操作系统负责)。

整合

HTTP 2.0默认使用TLS加密,那么除了TCP握手外,还需要建立TLS握手,这样需要消耗非常多的资源(即使TLS 1.3较TLS 1.2已做了优化)。在HTTP 3.0中,TCP握手与TLS握手整合到了一起。即0-RTT连接。

QUIC + UDP

QUIC基于UDP,一个连接上的多个流没有依赖,即使丢包只需要重新发送丢失的包即可,不需要重传整个连接,实现了多路复用

QUIC的帧中包含了Connection_Id字段,QUIC是通过该段识别连接的,而TCP是基于IP识别连接的,那么当网络环境变化的时候,Connection_Id并不会改变,能够迅速实现重连,能够提供更好的移动端表现

QUIC除了部分报文外,报文头部与报文BODY都经过加密,有效降低了安全风险

向前纠错,每个数据包除了它本身的内容之外还包括了其他数据包的数据,因此少量的丢包可以通过其他包的冗余数据直接组装而无需重传。

CDN

为什么需要CDN

  1. 物理因素的限制

    美国到中国的网络延迟大约为200ms,而中国到中国的网络延迟大约为20ms,这是由于光速的限制,即使是光纤也无法解决这个问题。

  2. 宽带成本的限制

    假如流量1元1G,发一个10G电影需要十块钱,并且我给10个人发同样的电影需要100元。

  3. 服务器成本的限制

    一台服务器假设能抗100G流量,而双十一的时候,我需要抗1000G流量,这时候我需要10台服务器,而且这10台服务器不是一年到头都在用,只有双十一的时候才会用到,这样就造成了资源的浪费。

CDN的益处

  1. 降低网络延迟

    CDN的作用就是让用户访问最近的服务器,这样就能降低网络延迟。

  2. 降低部署成本

    只需要部署少量的服务器,就能抗住大量的流量。

CDN的原理

一般来说,一个IP只能够对应一台服务器,如何实现用户访问最近的服务器呢?🕵️ - DNS劫持

  • 域名解析一般由网站自己处理
  • 要加速的域名则重定向到CDN厂商的域名解析服务处理
  • CDN厂商的域名解析服务会根据用户的IP地址,解析到最近的服务器
  • 用户直接访问最近的CDN服务器

::: info 一些问题

  • 地理距离可能更近,但是需要多次路由器节点转发
  • 如果用户指定某个DNS,如Google的8.8.8.8 :::

CDN策略

  1. 拉策略 (轻量资源)

    当用户访问一个资源的时候,CDN会先去源站拉取资源,然后再返回给用户。此时,如果CDN没有对应资源,就会返回404;一段时间后,CDN会丢弃资源。

  2. 推策略 (经常访问的资源)

    服务端主动告知CDN存储某些资源,丢弃某些资源。

WebSocket

1. 什么是WebSocket

  • 有状态的持久连接
  • 服务端主动推送消息
  • 用WebSocket发送信息比HTTP延迟低

::: details 一个🌰 ::: code-group

const { WebSocketServer } = require('ws');
    
const wss = new WebSocketServer({ port: 8080 });
​
wss.on('connection', function connection(ws) {
    ws.on('message', function incoming(message) {
        console.log('received: %s', message);
    });
​
    ws.send('something');
});
const WebSocket = require('ws');
​
const ws = new WebSocket('ws://localhost:8080');
​
ws.on('open', function open() {
   // 当建立连接的时候,向客户端发送一条信息
    ws.send('something');
});
​
ws.on('message', function message(data) {
   // 当收到来自服务端的消息的时候,打印出来
    console.log(`received: ${data}`);
});

:::

客户端在HTTP请求头增加:Connection: Upgrade+Upgrade: Websocket

服务端在接受请求后,返回101 Switching Protocols响应

网络安全

三要素

  1. 机密性:攻击者无法获取通信内容
  2. 完整性:攻击者对内容进行篡改时能被发现
  3. 身份验证:攻击者无法伪装成通信双方的任意一方与另一方通信

加密方式

  1. 对称加密:加密、解密使用相同的密钥
  2. 非对称加密:加密、解密采用不同的秘钥(公钥和私钥),公钥加密只能私钥解密,私钥加密只能公钥解密

密码散列函数(哈希函数)

  • 输入:任意长度的内容
  • 输出:固定长度的哈希值
  • 性质:找到两个不同的输入使之经过密码散列函数后有相同的哈希值,在计算上是不可能的

机密性

  • 加密需要加密算法和秘密钥信息
  • 网络传输是明文的,不安全

完整性与身份验证

  • 相互关联

如何实现完整性?

  • 明文m,哈希函数H,以及秘钥s
  • 计算H(m+s)获取哈希值h
  • mh组合成新的信息m+h
  • 接收方拆分m+h,重新计算H(m+s)h',对比h'h

如何实现身份验证

  • 签名:用于鉴别身份与防止伪造
  • 数字签名:对明文内容的哈希值使用私钥解密,验证者使用公钥验证