• 首先这篇讲http的文章不涉及最基础的http知识,比如什么是http协议,http协议常见的请求头,请求方式等等。主要是记录一些不常见的知识点。

TCP层影响对http时延的影响

http时延的根本是tcp时延,到底哪些时延影响了http呢?

常见对TCP时延,其中包括:

  • TCP连接建立连接(三次握手):

    • http在交换数据之前,需要建立连接,就是tcp的三次握手,需要耗费时间。
  • TCP慢启动和拥塞控制:

这里涉及的概念很多,所以我们要详细解释一下。

  • 通告窗口:

    • 技术解释:TCP流量控制的方法之一,在TCP两端在三次握手时就会声明自己接收窗口的大小来提供,窗口大小为字节数,每次发送ack确认数据包同时会传送当前的窗口大小,发送方发送的数据量不可以超过接收端窗口的大小,当窗口为0时,发送方将停止数据的发送
    • 举例解释:窗口就好像超市自动扶梯一样,一端的人下扶梯走进超市(数据被应用层接收),另一端的人从地下车库出来准备进入扶梯(另一端待发送的数据),如果扶梯上面的人满了(窗口大小为0)此时所有人只能在车库里面等
  • 拥塞窗口(cwnd):

    • 技术解释:TCP流量控制方法之一,如果说通告窗口是通过接收数据的一端进行的流量控制,那么拥塞窗口就是发送端进行的流量控制,发送端发送数据包的字节数不会超过拥塞窗口的大小
    • 举例解释:还是超市扶梯,这次在地库和超市门口各有一个门卫拿对讲机通报,地库的门卫第一次只放一个人(报文段)进去,根据慢启动算法,每次调整进去人的数量每次进去人的数量取通告窗口和拥塞窗口的较小值
  • 慢启动算法**
    • 具体算法
      • 当TCP握手完成后,拥塞窗口会被初始化为一个报文段大小,也就是每次只能发送一个报文段
      • 每收到一个ACK,拥塞窗口的大小就会翻倍增加,比如刚开始是1,然后是2,然后是4,最终到拥塞窗口的上限
      • 当到达拥塞窗口上限,此时将会进入拥塞避免算法**
  • 拥塞避免算法**
    • 具体算法:
      • 当进行拥塞避免时,cwnd每次收到ack后不在进行指数倍增加,而是每次加1
      • 当拥塞发生时,发送数据包丢失,例如超时确认或者重复的确认包,ssthress将会被设置为当前窗口(拥塞窗口和通告窗口的最小值)的一半
      • 如果是因为超时确认引起的数据包丢失,那么cwnd将会被初始化为1个报文段
  • 用于捎带确认对TCP延迟确认算法:
    • 首先,介绍一下什么是延迟确认算法。即接收方收到包后,如果暂时没有内容回复给发送方,则延迟一段时间再确认,假如在这个时间范围内刚好有数据需要传输,则和确认包一起回复。这种也被称为数据捎带。延迟确认只是减轻网络负担,未必可以提升网络性能,有些情况下反而会影响性能。
    • 然后,我们可以看到,发送端只有接收到确认报文才会继续发送数据,这个算法有时真的很影响网络传输性能。


  • Nagle算法和TCP_NODELAY

    • Nagle算法。如果每次只发送一个字节的内容而不优化,网络中将充满只有极少数 数据的数据包, 十分浪费网络资源,Nagle算法针对这种情况,要求缓冲区的数据达到一定数量或者一使定时间后才能将其发出,所小数据包将会被Nagle算法合并,以此来优化网络。这种优化虽然能使网络带宽被有效地使用,但是数据有可能被延迟发送
    • http应用程序常常会在设置参数TCP_NODELAY,禁用Nagle算法,提高性能
  • TIME_WAIT时延和端口耗尽

    • 我们先来看看端口耗尽的问题
    • client和server之间只能同时存在28233个TCP连接,这里指的是短连接,连接用完就释放掉了,端口应该也会释放掉,为啥还会产生端口耗尽的问题呢?

    • 这就需要提到TIME_WAIT这个状态了,TCP连接断开的时候,主动发起连接断开操作的一方,最后会停留在TIME_WAIT状态,会持续2*MSL的时长,这个状态的端口是不能被使用的,准确的说是当新的TCP连接的local IP remote IPremote PORT和TIME_WAIT状态的连接一致时这个端口不能被使用。0000

浏览器和服务器已经建立好连接,突然浏览器因为电脑断电关机,此时连接状态如何变化

如果是长连接,服务端的socket默认有一个SO_KEEPALIVE属性为true,如果2小时内在此接口的任一方向都没有数据交换,TCP就自动给对方发一个保持存活探测分节(keepalive probe)。这是一个对方必须响应的TCP分节.它会导致以下三种情况:

  • 对方接收一切正常:以期望的ACK响应(ACK是tcp包的一个标志位,意思是确认机器在线)。2小时后,TCP将发出另一个探测分节
  • 对方已崩溃且已重新启动:以RST(同样,RST也是tcp包的一个标志位,意思是重置连接)响应。套接口的待处理错误被置为ECONNRESET,套接口本身则被关闭
  • 对方无任何响应:源自berkeley的TCP发送另外8个探测分节,相隔75秒一个,试图得到一个响应。在发出第一个探测分节11分钟15秒后若仍无响应就放弃。套接口的待处理错误被置为ETIMEOUT,套接口本身则被关闭。如ICMP错误是“host unreachable(主机不可达)”,说明对方主机并没有崩溃,但是不可达,这种情况下待处理错误被置为EHOSTUNREACH

几个难懂的首部

connection首部

connection首部居然有2种功能, 很容易让人脑袋晕,我们来分别看看是哪两种功能:

  • 如果connection后面跟了一系列逗号分隔的首部字段名,当遇到第一个代理服务器的时候,会删除所列的这些首部字段名的信息,然后转发数据。举例子:假如http报文部分内容如下

    1. HTTP/1.1 200 OK
    2. Connectionmeter
    3. Metermax-use=3

    当这个报文遇到第一台代理服务器的时候,会删除掉meter信息。

  • 值为close,意思是完成操作之后,关闭这条持久连接,跟keep-alive相关。

理解HTTP协议头中的Vary

这部分转载自:转载于:https://my.oschina.net/yqz/blog/487590

  • 我们先看一下客户端和服务端如何对请求内容进行协商。
  • 服务端根据客户端发送的请求头中某些字段自动发送最合适的版本。可以用于这个机制的请求头字段又分两种:内容协商专用字段(Accept 字段)、其他字段。
  • 首先来看 Accept 字段,详见下表:
请求头字段 说明 响应头字段
Accept 告知服务器发送何种媒体类型 Content-Type
Accept-Language Accept-Language Content-Language
Accept-Charset 告知服务器发送何种字符集 Content-Type
Accept-Encoding 告知服务器采用何种压缩方式 告知服务器采用何种压缩方式

例如客户端发送以下请求头:

  1. 1. Accept:*/*
  2. 2. Accept-Encoding:gzip,deflate,sdch
  3. 3. Accept-Language:zh-CN,en-US;q=0.8,en;q=0.6

表示它可以接受任何 MIME 类型的资源;支持采用 gzip、deflate 或 sdch 压缩过的资源;可以接受 zh-CN、en-US 和 en 三种语言,并且 zh-CN 的权重最高(q 取值 0 - 1,最高为 1,最低为 0,默认为 1),服务端应该优先返回语言等于 zh-CN 的版本。
浏览器的响应头可能是这样的:

  1. 1. Content-Type: text/javascript
  2. 2. Content-Encoding: gzip

表示这个文档确切的 MIME 类型是 text/javascript;文档内容进行了 gzip 压缩;响应头没有 Content-Language 字段,通常说明返回版本的语言正好是请求头 Accept-Language 中权重最高的那个。

有时候,上面四个 Accept 字段并不够用,例如要针对特定浏览器如 IE6 输出不一样的内容,就需要用到请求头中的 User-Agent 字段。类似的,请求头中的 Cookie 也可能被服务端用做输出差异化内容的依据。

由于客户端和服务端之间可能存在一个或多个中间实体(如缓存服务器),而缓存服务最基本的要求是给用户返回正确的文档。如果服务端根据不同 User-Agent 返回不同内容,而缓存服务器把 IE6 用户的响应缓存下来,并返回给使用其他浏览器的用户,肯定会出问题 。因此,HTTP 协议规定,如果服务端提供的内容取决于 User-Agent 这样「常规 Accept 协商字段之外」的请求头字段,那么响应头中必须包含 Vary 字段,且 Vary 的内容必须包含 User-Agent。同理,如果服务端同时使用请求头中 User-Agent 和 Cookie 这两个字段来生成内容,那么响应中的 Vary 字段看上去应该是这样的:

  1. Vary: User-Agent, Cookie

也就是说 Vary 字段用于列出一个响应字段列表,告诉缓存服务器遇到同一个 URL 对应着不同版本文档的情况时,如何缓存和筛选合适的版本。

场景

  1. 浏览器发起HTTP请求。
    2. 请求达到缓存服务器。
    3. 缓存服务器服务器查看自身是否存在请求的资源,如果存在,则将资源直接返回到浏览器,否则将请求转发给web服务器。
    4. web服务器处理请求,将响应的资源返回给缓存服务器。缓存服务器查看HTTP头中是否包含Vary字段。如果有,则读取对应的值,以及这些值对应的字段,按字段值分类存储收到的响应资源。
    5. 缓存服务器将响应资源返回给浏览器。
    比如,Http Response 协议头中含有Vary: Accept-Encoding,意味着该缓存服务器会根据协议头中的Content-Encoding字段来分别缓存压缩和非压缩资源。当客户端发起http请求时,缓存服务器会根据http协议头中是否包含Accept-Encoding字段来决定是否返回压缩过的资源。