3453 字
17 分钟
小林计算机网络笔记

链接 幂等性: 重复请求得到的结果是一样的

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/basic q:质量因子

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四次握手:

  1. 客户端发起加密通信请求,并发送一个随机数,同时发送自己使用的TLS协议版本
  2. 确认TLS版本,回发一个服务端生成的随机数,确认算法等密码套件
  3. 客户端先通过CA公钥确认数字证书的合法性,如果合法就用解密的服务器公钥加密报文,并发送一个服务器公钥加密的随机数;今后使用公钥加密的通知;以及密钥交换结束的通知
  4. 服务端收到第三个随机数,通过协商的算法进行加密,计算出本次通信的会话密钥,然后发送今后使用公钥加密的通知;以及密钥交换结束的通知

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的区别

  1. 连接
  • TCP面向连接
  • UDP无连接
  1. 服务对象
  • TCP一对一
  • UDP一对一或一对多,多对多
  1. 可靠性
  • TCP可靠
  • UDP不可靠
  1. 分片
  • TCP在传输层分片(如大于MSS)
  • UDP在IP层分片(如大于MTU)
  1. 首部开销
  • TCP最小20字节
  • UDP 8字节
  1. 拥塞控制,流量控制
  • TCP有拥塞控制
  • UDP没有
  1. 传输方式
  • 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全连接队列的使用情况

Terminal window
1 -l 显示正在监听(listening)的socket
2 -n 不解析服务名称
3 -t 只显示tcpsocket

netstat -s | grep overflowed 可以查看全连接队列溢出情况 如果持续不断地有连接因为 TCP 全连接队列溢出被丢弃,就应该调大 backlog 以及 somaxconn 参数。

防范SYN攻击:

  1. 增大全连接队列
  2. 开启 tcp_syncookies
  3. 减少SYN/ACK重传次数

如何优化TCP#

三次握手的性能提升#

客户端优化

  • 降低超时重传次数上限 服务端优化
  • 增大半连接队列容量
  • 开启syncookie
  • 开启TCP_FastOpen功能(绕过三次握手)

四次挥手的性能提升#

即使 close() 被调用,内核还是会接收 ACK、发送 ACK ——只是不能再用这个 socket 做读写了

主动方

  • 降低FIN_WAIT1状态下的重传数
  • 复用处于TIME_WAIT状态下的连接
  • 增大TIME_WAIT上限个数 被动方
  • 降低FIN_WAIT状态下的重传数

存在TIME_WAIT状态的原因(默认60s)

为什么关闭同个端口的TCP马上重连会显示端口占用的原因

  1. 为了防止历史连接中的数据影响下一次同个四元组的TCP连接
  2. 保证被动关闭的一方能够正常关闭

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状态

小林计算机网络笔记
https://fuwari.vercel.app/posts/小林计网/
作者
Lorem Ipsum
发布于
2025-06-17
许可协议
CC BY-NC-SA 4.0