HTTP
一、HTTP 准备阶段
HTTP是基于TCP的上层协议 所以要先建立链接 也就是三次握手 HTTP1.1 版本以后就增加哀乐Keep-Alive 一次TCP链接可以在多次请求中使用
二、HTTP 请求的构建过程
HTTP 报文分3部分
- 请求行
请求的URL、 HTTP 版本、请求方法(GET/POST/…) - 请求首部
Accept-Charset 表示客户端可以接受的字符集
Content-Type 表示正文格式 例如JSON
Cache-control 控制缓存 当客户端中包含max-age指令时 如果客户端指定的时间大于缓存时间 那么可以直接用 max-age 如果为0 缓存层就会把请求转发给应用集群
If-Modified-Since 如果服务端某个资源在某个时间更新了 那么客户端就应该下载最新的资源 如果没有更新就会返回 304 Not Modified - 正文实体
三、HTTP 请求的发送
- HTTP是基于TCP协议的,把二进制流传到TCP层,TCP层把二进制流变成报文发送给服务器,在发送每一个报文的时候都要有对方的一个ACK,如果没有回应TCP这一层会进行重新传输。
- TCP发送每一个报文的时候 都要加上自己的IP地址和要到的IP地址 交给IP层进行传输
- IP层要查看自己的IP地址和目标IP地址是否在同一个网段,如果在就发送ARP协议请求这个目标IP地址的Mac地址 ,将源Mac地址和目标Mac地址放入MAC头,发出即可。如果不在同一个网段,那么就会通过ARP协议获取网关的MAC地址,然后将源Mac地址和网关Mac地址放入Mac头 发出去
- 网关收到包后发现Mac地址符合 取出IP地址 根据路由协议配置的下一跳路由 获取下一跳路由的Mac地址 将包发送到下一跳路由器。
- 一跳一跳发送之后 最后到达目标IP地址所在的局域网,在局域网上发送ARP请求,获得这个目标地址的Mac地址 将包发出去。
- 目标机器发现 Mac地址符合 就把包收进来 发现IP地址符合,根据IP协议 知道自己的上层是TCP 于是解析TCP头 里边有包序号 然后把对应的包返回一个ACK,放入自己的缓冲区,如果不是自己需要的包需要就丢弃。
- TCP头里还有端口号,HTTP服务器正在监听这个端口 于是目标机器就知道是那个HTTP服务器进程想要这个包。
四、HTTP 返回的构建
- 状态行 例如 200 大吉大利 404 失败找不到
- 首部
- 实体
HTTP 2.0
- 头部压缩 不会像HTTP1.0/1.1 每次都将头部字段穿过去 而是会在通信的两端建立头部字段的索引表,每次只会传输索引
- IO多路复用 HTTP 2.0 将一个TCP链接中 切分成多个流 每个流都有自己的ID ,只是一个虚拟通道 流是有优先级的。
- 通过这两种机制 客户端可以将多个请求分到不同的流中,多个流只是一个虚拟的概念 HTTP 2.0可以让多个请求真正实现并行 每个请求的流标示不同 到达目的地之后再根据流标示重新组装
HTTP 2.0 还是基于TCP的协议 所以有严格的顺序要求 ,采用多个流 让TCP看起来并行了 但是数据之间没有关联的情况下很好。如果数据之间有关联,其中一个包出现问题 TCP还是要等重传完成之后才会继续,如果数据之间有关联 前一个stream1没到 stream2同样也会阻塞。
基于UDP的QUIC协议
- 自定义链接机制
采用一个64位随机数作为链接标示 只要这个数不变 就认为链接没有断开 - 自定义重出机制
TCP中的超时重传,通过自适应重传算法 采样RTT时间来不断调整 这样算出来的时间是不准确的
QUIC 也有个序列号 是递增的。任何一个序列号的包只发送一次 下一次就要加一了,例如 第一次发送 是 100 但是没有确认 有发送一个101 这样回来的确认包100就是第一个包 101就是第二个包 所以更准确。如何知道100和101是同一个包呢 这里会记录一个offset用于标记 - 无阻塞的多路复用
QUIC 是基于UDP的 同一条QUIC链接上可以创建多个stream 是没有依赖的 这样假设stream2丢了一个UDP包 stream3 包 无需等待 就可以发给用户 - 自定义流量控制
TCP的ACK是累计应答 一旦ACK了一个序列号 就说明前面的都到了 所以只要前面的没到 后面的到了也不能ACK 就会导致后面的到了 也有可能超时重传 浪费带宽
QUIC的ACK是基于offset的 每个offset的包来了 进了缓存就可以应答 应答后就不会重发 中间空档会等待到来或者重发即可,窗口的起始位置为当前收到的最大offset offset到当前的stream所能容纳的最大缓存是真正的窗口大小 更加准确。