链接 幂等性: 重复请求得到的结果是一样的
HTTP
缓存技术
HTTP 缓存有两种实现方式,分别是强制缓存和协商缓存。 ![[截屏2025-06-17 00.02.02.png|535x449]] 强制缓存 浏览器判断缓存没有过期就直接使用浏览器的本地缓存,主动权在浏览器 协商缓存 与服务端协商后,通过协商结果判断是否使用缓存
- 时间
- ETag
注意,协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
怎么优化HTTP/1.1
- 避免发送HTTP请求
- 缓存
- 减少HTTP请求次数
- 减少重定向次数
- 合并请求
- 比如网站小图片利用
CSS Image Sprites技术合并
- 比如网站小图片利用
- 延迟发送请求
- 减小响应数据大小
-
无损压缩
content-encoding(gzip,brotli) -
有损压缩
Accept: audio/*; q=0.2, audio/basicq:质量因子
-
HTTP 2.0
优点
- 头部压缩
- 二进制帧
- 并发传输
- 服务器主动推送 缺点
- 队头堵塞
HTTP 3.0
美中不足的HTTP2.0 队头堵塞造成了很大的性能瓶颈,但它其实是tcp协议本身的缺陷,所以3.0改用udp协议 ![[截屏2025-07-18 15.39.39.png|426x396]]
由于tcp是字节流协议,当有包丢失时,后续的包因为序号对不上,只能卡在缓存里,无法接受,在接收方看来就是堵塞
TLS握手延迟 每次发起http请求,都要进行tcp三次握手和tls四次握手,而且由于tcp本身的“拥塞控制”特点引起的慢启动特性,产生了延迟 QUIC协议 HTTP3.0通过QUIC协议实现 还有一个特点是:==QUIC实现在用户层面,相比TCP在内核层面,更加容易更新迭代==
HTTPS
S指”TLS/SSL”加密
为什么要引入HTTPS
因为http的明文传输导致了极大的安全隐患 为了解决这个问题,首先想到的是对称加密,但是对称加密无法保证密钥本身传输的安全性 于是引入==摘要算法和数字签名== 摘要算法和数字签名 摘要算法就是对传输内容取Hash 数字签名就是用发送者的私钥对内容进行加密,接收方用发送方公开的密钥进行解密 但是这样虽然表面上传输安全,但是如果有怀有恶意的人把自己的公钥发给接收方,再用自己的私钥对伪装的内容加密,这样接收方也无法判断内容的真实性,这主要的问题就是:==如何证明发送方的身份==,于是引入权威机构来为发送方证明,这就是==数字证书== 数字证书 发送方将自己的公钥给权威机构(CA),CA用自己的私钥对发送方公钥等内容(域名,有效期等)进行签名,加密的结果就是==数字证书==,这样接收方收到内容后可以拿证书用CA的公钥解密证书的签名,如果发现解密结果的hash和计算的的证书的hash一致,就告知接收方发送方的身份合法,由此保障传输安全
操作系统(如 Windows、macOS)、浏览器(如 Chrome、Firefox)或 HTTP 客户端(如 cURL)内置了全球受信任的 根 CA 证书列表(包含公钥)
HTTPS如何建立连接的
多了一层TLS/SSL层 TLS四次握手,利用RSA算法或者ECDHE算法交换密钥,之后就是用这个密钥进行加密的HTTP通信
TLS四次握手:
- 客户端发起加密通信请求,并发送一个随机数,同时发送自己使用的TLS协议版本
- 确认TLS版本,回发一个服务端生成的随机数,确认算法等密码套件
- 客户端先通过CA公钥确认数字证书的合法性,如果合法就用解密的服务器公钥加密报文,并发送一个服务器公钥加密的随机数;今后使用公钥加密的通知;以及密钥交换结束的通知
- 服务端收到第三个随机数,通过协商的算法进行加密,计算出本次通信的会话密钥,然后发送今后使用公钥加密的通知;以及密钥交换结束的通知
HTTPS如何保障内容的完整性
TLS记录协议把内容分成多个数据端,分别进行压缩,同时附上一个MAC值(哈希值)用来保证数据的真实性,再一起通过对称密码进行加密,并添加报头
HTTPS是绝对安全的吗
中间人攻击 例如:伪装基站截获信息转发给中间服务器,建立TLS连接后再和真正服务端建立连接,这样就能偷看数据了
但前提是客户端选择接受中间服务器的数字证书,这个证书往往能被识别出是不正确的
现代浏览器首选**ECDHE + RSA
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- 密钥交换:ECDHE(客户端与服务器协商出会话密钥)
- 签名验证:RSA(用于验证服务器证书或 ECDHE 参数)
- 安全性: 支持前向保密
HTTPS性能优化
损耗在哪?
- 第一个环节, TLS 协议握手过程;
- 第二个环节,握手后的对称加密报文传输。
如何优化
- 硬件,软件
- 协议优化
- 密钥交换过程选择ECDHE而不是RSA算法(ECDHE第三次抢跑,RSA 密钥交换算法的 TLS 握手过程慢且长)
- TLS升级
合并,密码套件升级(防==降级攻击==)
- 证书优化
- 周期请求并缓存
- 会话复用
- SessionID
- Session Ticket
- ==重放攻击== ->对会话密钥设定一个合理的过期时间
RPC
本质上不算协议,而是一种调用方式 RPC 有很多种实现方式,不一定非得基于 TCP 协议 早期C/S架构使用RPC而B/S架构使用HTTP,现在区分不明显,RPC常用于公司内部多个微服务直接的通信
WebSocket
服务器推送方案
- HTTP不断轮询
- 长轮询 这两种只适用于简单场景,当可能会有大量消息主动推送时,就要考虑websocket了
TCP
基本认识
如何确定TCP连接 TCP四元组可以唯一确定一个连接
- 源地址
- 源端口
- 目的地址
- 目的端口 TCP连接上限 取决于客户端的ip数和端口数 但服务端的最大并发连接数肯定达不到理想值 因为:1.系统限制 2.内存限制
TCP和UDP的区别
- 连接
- TCP面向连接
- UDP无连接
- 服务对象
- TCP一对一
- UDP一对一或一对多,多对多
- 可靠性
- TCP可靠
- UDP不可靠
- 分片
- TCP在传输层分片(如大于MSS)
- UDP在IP层分片(如大于MTU)
- 首部开销
- TCP最小20字节
- UDP 8字节
- 拥塞控制,流量控制
- TCP有拥塞控制
- UDP没有
- 传输方式
- TCP基于字节流
- UDP基于数据报
TCP连接建立
- 客户端 TCP 连接 TIME_WAIT 状态过多,会导致端口资源耗尽而无法建立新的连接吗?
会的,如果客户端每次都用新端口,老端口都处于TIME_WAIT状态,那可会导致端口耗尽,无法发起新连接
三次握手 ==第三次握手是 可以携带数据的,前两次握手是不可以携带数据的==
如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP的保活机制
也可实现心跳机制,设置定时器,规定时间内未发起请求,定时器时间一到就释放 如果已经建立了连接,但是服务端的进程崩溃会发生什么? 会交给内核释放资源,但同时也能完成和客户端的四次挥手
TCP 特性
重传机制
超时重传 ==时间驱动重传== 超时时间是动态变化的 快速重传 ==数据驱动重传 ![[截屏2025-07-21 10.35.09.png|484x370]]== 问题在于:重传是重传一个还是重传所有?
- SACK
头部附加上已经传输的数据 - D-SACK:告诉「发送方」有哪些数据被重复接收了
流量控制
滑动窗口 swnd rwnd 滑动窗口并非一成不变的,发送窗口和接收窗口存放的字节都是放在操作系统的缓冲区内的,会被操作系统调整
![[22.jpg.webp]]
那如果系统缓存和窗口大小同时减小呢? 可能会导致丢包 为了防止这种情况发生,TCP 规定是不允许同时减少缓存又收缩窗口的
如果窗口调整ACK丢失呢?
为了解决这个问题TCP为每个连接都设置了==持续定时器==,只要有一方收到了对方的零窗口通知,就启动定时器,如果定时器超时,就会发送窗口探测 ( Window probe ) 报文,请求对方当前的窗口大小,如果连续3次都是0,可能就会发送
RST关闭连接
糊涂窗口综合症
简单来说,就是窗口越缩越小,导致每次传输成本过大 ![[26.png.webp]]
解决方法: 接收方:不发送小窗口通知 发送方: 避免发小数据(Nagle算法)
if 有数据要发送 { if 可用窗口大小 >= MSS and 可发送的数据 >= MSS { 立刻发送MSS大小的数据 } else { if 有未确认的数据 { 将数据放入缓存等待接收ACK } else { 立刻发送数据 } }}拥塞控制
为什么要有拥塞控制?
- 因为流量控制只是对发送方接收方来说的,没有考虑网络状况
cwnd:拥塞窗口(swnd=min(cwnd,rwnd)) 拥塞就缩小,反正扩大
怎么知道当前网络是否出现了拥塞呢?
- 看有无超时重传现象
主要是四个算法:
- 拥塞避免
- 慢启动
- 拥塞发生
- 快速恢复
慢启动:当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1
慢启动的上限叫做慢启动门限ssthresh
- cwnd<ssthresh:慢启动算法
- cwnd>ssthresh:拥塞避免算法 ![[截屏2025-07-21 17.24.56.png]]
TCP 半连接队列和全连接队列
![[3.jpg.webp|506x506]]
ss命令:查看TCP全连接队列的使用情况
1 -l 显示正在监听(listening)的socket2 -n 不解析服务名称3 -t 只显示tcpsocketnetstat -s | grep overflowed 可以查看全连接队列溢出情况
如果持续不断地有连接因为 TCP 全连接队列溢出被丢弃,就应该调大 backlog 以及 somaxconn 参数。
防范SYN攻击:
- 增大全连接队列
- 开启 tcp_syncookies
- 减少SYN/ACK重传次数
如何优化TCP
三次握手的性能提升
客户端优化
- 降低超时重传次数上限 服务端优化
- 增大半连接队列容量
- 开启syncookie
- 开启TCP_FastOpen功能(绕过三次握手)
四次挥手的性能提升
即使 close() 被调用,内核还是会接收 ACK、发送 ACK ——只是不能再用这个 socket 做读写了
主动方
- 降低FIN_WAIT1状态下的重传数
- 复用处于TIME_WAIT状态下的连接
- 增大TIME_WAIT上限个数 被动方
- 降低FIN_WAIT状态下的重传数
存在TIME_WAIT状态的原因(默认60s)
为什么关闭同个端口的TCP马上重连会显示端口占用的原因
- 为了防止历史连接中的数据影响下一次同个四元组的TCP连接
- 保证被动关闭的一方能够正常关闭
TCP传输数据的性能提升
- 扩大窗口大小
- 扩大发送方/接收方缓冲区
- 调整内存范围
为什么每次TCP建立连接时,序列号都不一样呢
为了避免该四元组受到上一次连接的数据干扰
同样设计目的的还有TIME_WAIT状态
PAW机制:防止TCP包中的序列号发生绕回 开启tcp_timestamp的情况下,连接双方维护一个时间戳,每收到一个包就对比看时间戳是否是递增的,不是就丢弃 什么时候SYN报文会被丢弃
-
如果同时开启recycle和timestamp,就会开启叫做
per-host的PAW机制,这种机制不对四元组作检查,而是只对ip做检查 -
所以如果客户端通过NAT网关,A,B客户端显示为同一ip,而有一方的时间戳比较小,就会导致其包被认为超时而丢弃
-
有一方的半连接队列或全连接队列满了
服务端收到SYN请求后,内核把该连接储存到半连接队列(SYN队列)中,当完成三次握手后,再把连接从半连接队列拿出放到全连接队列中(Accept队列),等待进程取出
已建立的TCP,收到SYN会发生什么
服务端收到客户端重连发送的SYN(乱序),会返回正常顺序的ACK,客户端发现序列号不是自己想要的,就会发送RST终止连接
如何优雅关闭一个TCP连接?
- KILL(❌)
- killcx 通过伪造四元组骗取正确序列号,再伪造正确序列号终止连接(主动)
- tcpkill 监听,伪造正确序列号(被动)
四次挥手中收到乱序的FIN包怎么处理
会加入乱序队列,等到收到正常的数据包再检查乱序队列看是否有可用数据包,有的话才进入TIME_WAIT状态