计算机网络概论
笔者:YDSUPER
课程地址:点我前往
零、前言
课程介绍
- 通过一个示例建立对计算机网络的整体认识
- 建立对网络协议分层的认知
- 分析HTTP1、2、3的关系
- 介绍CDN运行的基本原理
- 了解网络安全的最基本原则
分析方法
自底向上
- 从简单开始,逐渐变复杂
- 将模块逐步拼凑成一个系统
自顶向下
- 从复杂开始,逐渐变简单
- 从复杂的系统问题入手,拆分为模块问题
一、蟹堡王帝国
利用蟹堡王故事渐入勾勒庞大的网络体系
三步走战略
- 在比奇堡开通外卖
- 在北京和上海开分店
- 在全国开分店并开通外卖
小结
- 蟹堡王顾客:客户端
- 蟹堡王分店:服务端
- 小区转发点和蟹堡王城市转发分店:路由器
- 转发表格:网络协议
二、计算机网络基础
网络组成部分
- 主机:客户端和服务端
- 路由器
- 网络协议
网络结构:网络的网络
- 比奇堡和小区网络:本地网络
- 北京和上海分店+比奇堡:三个本地网络节点的网络
- 全国通信网络:本地网络的网络
- 区域网络、城域网和广域网
电路交换&分组交换
-
电路交换
需要双方建立连接后,沿着此路径进行数据传输,此时其他连接就会被阻断
-
分组交换
现代计算机网络主要使用的通信技术
网络分层
- 快递员不关心包裹内容(应用层)
- 卡车司机不关心车厢里拉的是什么(运输层)
- 高速公路不关心开的什么车(网络层)
网络协议
协议定义了在两个或多个通信实体之间交换的报文格式和顺序,以及报文发送和/或接受一条报文或其他事件所采取的动作。
标头和载荷
数据传输过程中,标头和载荷作为数据包或帧的开头部分和主体部分,标头包含了传输数据的控制信息,载荷包含了实际要传输的数据。
小结
- 网络组成部分:由主机、路由器、交换机等组成
- 网络结构:网络的网络
- 信息交换方式:电路交换和分组交换
- 网络分层:分清职责,物理层、链路层、网络层、运输层和应用层
- 网络协议:标头和载荷
三、Web中的网络
HTTP 协议
如图,我们利用基本示例诠释其结构:(红色字体为请求, 蓝色为响应)
请求部分(红色字体)
请求由三部分构成:请求行、消息报头、请求正文。
GET / HTTP/1.1
Host: info.cern.ch
Connection: keep-alive
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (windows NT 10.0; Win64; 64) Applewebkit/537.36 (KHTMl, like Gecko) Chrome/108.0.0.0 Safari/537,36 Edg/108.0.1462.42
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip,deflate
Accept-Language: zh-CN,zh;g=0.9,en;q=0.8,en-GB;q-0.7,en-US;g-0.6,zh-TW;q=0.5
- 起始行(第一行):包含三要素: 请求的方法
GET,请求资源路径/,HTTP的版本HTTP/1.1 - Host(第二行):指定目标的服务器域名
- Connection(第三行):是否需要持久连接(HTTP1.1 默认进行持久连接)
keep-alive即进行长连接 - User-Agent(第六行):描述客户端的信息,含操作系统、浏览器版本信息等。
- Accept(第七行):指定客户端能够接收的内容类型
- Accept-Encoding(第八行):指定浏览器可支持的web服务器返回内容的压缩编码类型
- Accept-Language(第九行):浏览器可以接受的语言
注:只有在发送 POST 请求时才会有请求正文,GET 方法并没有请求正文(如上方示例就没有)
响应部分(蓝色字体)
响应也由三部分构成:状态行、消息报头、响应正文。
HTTP/1.1 200 0K
Date: Tue,13 Dec 2022 09:54:08 GMT
Server: Apache
Last-Modified: wed,05 Feb 2014 16:00:31 GMT
ETag:"286-4flaadb3105c0"
Accept-Ranges: bytes
Content-Length: 112
Connection: close
Content-Type: text/html
<!DOCTYPE html>
<html><head>YDSUPER</head>
<body><h1>Hello World~</h1></body>
</html>
- 状态行:三要素: HTTP版本、状态码、状态信息
- Date:响应的日期和时间
- Server:服务器软件和版本信息
- Last-Modified:请求资源的最后修改时间
- Accept-Ranges:是否接受获取某个实体的一部分(如文件的一部分)
bytes表示接受 - Content-Length:响应的内容长度
- Connection:表示连接的状态,是否持久连接。
close即服务器响应后关闭 TCP 连接 - Content-Type:响应体的MIME类型(媒体类型)
- 响应正文:响应体实际返回的数据,通常是HTML、JSON、XML等等格式内容
HTTP 连接模型
- 短连接模型:HTTP1.0时代 所使用的
Short-lived connections每次 HTTP 请求和响应都需要和服务器建立一个新的 TCP 连接。每次新建连接和关闭都会消耗性能,不适用于处理并发请求,且无法在一条连接上实现多路复用,在一个完整请求中间若插入其他请求 也会导致HTTP无法分辨这部分内容是来自哪个请求,很多数据会重复发送。 - 持久连接模型:HTTP1.1开始默认使用持久连接模型
Persistent connection,解决了重复建立 TCP 连接的问题,但是对于队头堵塞无法很好解决,哪怕很小的请求也需要等前一个请求返回才能请求下一个请求,最终可能导致完成所有请求花费的时间远大于其实际所花费时间。 - HTTP管线模型 :允许在一个请求上,连续发送多个请求。服务器会按照顺序执行这些请求,依次响应。这种模型大大提高了资源利用率和性能。
HTTP1.1:无法多路复用
在一条 TCP 连接上,HTTP报文是严格按顺序的。 思考:如果服务器将2个响应交替发送,会是什么样的结果?
通过下面的示例,告诉你结果,为什么无法多路复用
// main.js
console.log('hello ydsuper');
/* style.css */
body {
color: red;
}
上述2个代码块,分别代表不同的文件,服务器交替响应给客户端上述2个文件,下面是客户端接收到的结果
body {
console.log('hello ydsuper');
color: red;
}
通过上述实例,客户端是无法判断哪个结果的每一行是属于哪个请求的。因此就无法实现多路复用。
HTTP2:帧
将多个http请求拆分到帧里面,每个帧都会携带来自不同http请求的数据,进行实现多路复用。
1. +----------------------------------+
2. | Length(24) |
3. +------------+------------+----------+
4. | Type(8) | Flags(8) |
5. +-+----------+------------+-----------------------+
6. Stream Identifier(31) |
7. +-+===============================================+
8. | Frame Payload(0...) ...
9. +-------------------------------------------------+
解析上述帧图: 开始的3个字节:表示帧的长度 第四个字节:表示帧的类型 第五个字节:对于不同的帧有不同的含义,用于传递当前帧的一些状态 第六个字节:第一位是保留位,后面的31位代表这个帧所属流的ID 再往后:当前帧的长度,即当前帧的载荷,通过每个帧的头部信息,就可以在每个帧中分析出当前帧属于哪个流,进而可以确定每个帧的载荷属于哪个请求,最终在服务器或浏览器重组为完整的 请求和响应
通过上述方式,最终实现 HTTP2 的多路复用
帧带来的额外好处:
- 调整响应传输的优先级
- 头部压缩
- Server Push
上述功能都可以通过不同的帧实现,这在 HTTP1.1 中无法实现。
思考:HTTP2 已经解决了多路复用的问题,为什么还有 HTTP3 呢? 简单来说:HTTP3 出现的原因是 HTTP2 还不够快,也为了解决 HTTP/2 中仍然存在的一些问题和局限性 (HTTP2 在 TCP 上仍然可能出现对头堵塞)
HTTPS 在 HTTP 之上增加了一层 TLS 或者 SSL 协议 HTTP 和 TLS 的分裂 导致了 HTTPS 双倍的握手延迟,即 TCP 和 TLS 延迟
HTTP2:TCP上的队头堵塞
- TCP 包0:包含了(包含了 style.css 的第1行内容)的 HTTP2的帧
- TCP 包1:包含了(包含了 main.js 全部内容)的HTTP2的帧
- TCP 包2:包含了 (包含了 style.css 的第2行内容)的 HTTP2的帧
- TCP 包3:包含了(包含了 style.css 的第3行内容)的HTTP2的顿
HTTP2:3 RTT 启动
- TCP连接1个RTT 2.TLS建立连接2个RTT
HTTP3:QUIC
全称:Quick UDP Intervet Connection
- 现存网络设备对 TCP 和 UDP 支持已经僵化
- UDP 不靠谱但是 QUIC 靠谱(包丢了就不管了)
- QU1C 可以为除HTP协议以外的应用层协议提供支持
CDN
普通服务器:
- 无法突破物理界限的
- 重复发送相同内容,消耗相同的流量和金钱
- 流量高峰顶不住
CDN:
-
DNS劫持
- 域名解析一般由网站自己处理
- 要加速的域名则重定向到 CDN 广商的域名解析服务处理
- CDN 厂商根据来源确定最近的 CDN 服务器的 IP
- 用户直接访问最近的 CDN 服务器
-
缓存策略
- 拉策略(用户自己选
- 推策略(直接发给客户
WebSocket
- 有状态的持久连接
- 服务端可以主动推送消息
- 用 WebSocket 发送消息延迟比 HTTP 低
// 服务端代码
const { WebSocketServer } = require('ws');
const wss = new WebSocketServer({ port: 808 });
wss.on('connection', function,connection(ws) [
// 有新连接时监听来自客户端的消息
ws.on('message', function message(data) {
// 打印收到的消息,再把消息原封不动地发回给客户端
console.log('received: %s', data); ws.send(data);
1);
// 客户端代码
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:880');
ws.on('open', function open() {
//当连接建立时,向服务端端发送一条消息
ws.send( ' something');)
});
ws.on( 'message', function message(data) {
//当收到来自服务端的消息时,打印出来
console.log('received: %s',data)1);
})
小结
- HTTP 1 2 3 的演进历史
- CDN 解决了 HTTP 协议之外的问题
- WebSocket 从 HTTP 协议升级而来
四、网络安全
网络安全三要素
- 机密性:攻击者无法获取通信内容
- 完整性:攻击者对内容进行篡改时能被发现
- 身份验证:攻击者无法伪装成通信双方的任意一方与另一方通信
对称加密和非对称加密
-
对称加密:加密、解密用同样的密钥
-
非对称加密:加密、解密是要不同的密钥(公钥和私钥),而且公钥加密只能用私钥解密,私钥加密只能用公钥解密·
密码散列函数(哈希函数)
- 输入:任意长度的内容
- 输出:固定长度的哈希值
- 性质:找到两个不同的输入使之经过密码散列函数后有相同的哈希值,在计算上是不可能的
机密性
- 加密需要加密算法和密钥等信息(统称为秘密信息)
- 网络是明文的,不安全
完整性和身份验证
完整性和身份验证相互关联
- 我向银行申请转账
- 银行需要确认
- 此请求真的是我本人发起的
- 目标账户和转账金额没有被纂改
如何实现机密性
- 已知:网络是明文的
- 如果双方可以通过明文通信商量出秘密信息,那么攻击者也可以
- 所以想要通过明文通信交换秘密信息,通信双方需要先有秘密信息
如何实现完整性
-
密码散列函数性质:找到两个不同的输入使之经过密码散列函数后有相同的哈希值,在计算上是不可能的
-
有明文m,密码散列函数 H
-
计算 H(m) 获得哈希值 h
-
将m和h组合成新信息 m+h
-
接收方拆分 m+h,重新计算 H(m) 得 h',对比 h'和h
-
有明文 m,密码散列函数 H,以及一个密 s
-
计算 H(m + s) 获得哈希值 h
-
将m和h 组合成新信息m +h
-
接收方拆分m +h,重新计算 H(m + s) 得 h’,对比 h’ 和h
所以想要实现完整性,通信双方需要先有秘密信息
如何实现身份验证
-
签名:用于鉴别身份和防止伪造
-
非对称加密性质:加密、解密使用不同的密钥(公钥和私钥),而且公钥加密只能用私钥解密、私钥加密只能用公钥解密
-
蟹老板用自己的私钥对信件进行加密,并发送给海绵宝宝
-
海绵宝宝使用蟹老板的公钥进行解密,获得原文
-
保证了机密性、完整性和身份验证
-
数字签名: 对明文内容的哈希值使用私钥加密,验证者使用公钥验证
-
数字签名(指纹) = 私钥加密(密码散列函数(原文))
-
消息 = 原文 + 数字签名
-
一般用于对公开内容(如包含公的证书)进行数字签名,防止篡改
HTTPS
把 HTTP 的铭文换成密文,再验证身份,即 HTTPS
HTTPS = HTTP = TLS TLS = 身份验证 + 加解密 身份验证靠 PKI(Public Key Infrastructure,公钥基础设施)
服务端身份验证靠 PKI,客户端身份验证靠 HTTP 协议
小结
- 网络安全三要素: 机密性、完整性和身份验证
- 在没有提前交换秘密信息的前提下,无法在不安全的信道交换秘密信息
- PKI 保证了普通用户不需要“面对面”和根证书机构交换根证书
- HTTPS 使用 PKI 完成了除客户端身份验证以外的特性,客户端身份验证靠HTTP 协议实现