HTTP解析(一)HTTP报文

HTTP浅析(一)HTTP报文

HTTP报文

  1. 起始行
  2. 首部
  3. 主体(非必须)

结构图

HTTP报文结构图

连接管理

从浏览器键入地址到连接结束的过程是什么?

连接过程

TCP为HTTP提供一条可靠的比特传输管道,从TCP连接一端填入的字节会从另一端以原有的顺序、正确地传送出来。

HTTP和HTTPS的区别?

TCP连接持续不断地进行

TCP连接根据四个值来识别

  1. 源IP地址
  2. 源端口号
  3. 目的IP地址
  4. 目的端口号

这四个值唯一确定了一条连接,任意一条不相同的连接必然这四个值不会完全相同。

TCP结构是什么?

TCP结构图

如何用Socket实现HTTP事务?

如何用Socket实现HTTP事务

TCP客户端和服务器如何通过Socket通信?

通过Socket通信

HTTP事务的时延有哪些原因?

由于和建立TCP连接相比,事务处理时间是很短的,除非在处理很复杂的动态资源,否则HTTP的时延就是由TCP网络时延导致的。

  1. 如果最近没有对URI中的主机名访问,通过DNS解析系统要转换IP需要花费数十秒。
  2. TCP每次连接都需要三次握手,这个值最多一两秒,但是连接多的话会累加上去(非HTTP2.0的情况)
  3. 一旦连接建立,读取请求报文,传输请求报文,处理请求报文都需要时间。
  4. 回送HTTP相应也需要时间。

我们应该从哪些方面来提升TCP的性能?

  1. TCP连接建立握手
  2. TCP慢启动拥塞控制
  3. 数据聚集的Nagle算法
  4. 用于捎带确认的TCP延迟确认算法
  5. TIME_WAIT时延和端口耗尽

什么是TCP的延迟确认机制?

由于因特网无法确保可靠的分组传输(因特网路由器超负荷的话,可以随意丢弃分组,所以TCP实现了自己的确认机制来确保数据的成功传输)

TCP延迟确认

什么是TCP慢启动?

TCP面对大量的数据,不会一次性将所有分组都发出去,TCP会随着时间进行自我“调谐”,起初会限制连接的最大速度。如果成功则会逐渐加大传输速度,简单来说:

发送一个分组 -> 确认发送成功 -> 具备一次性发送两个分组的权限 -> 发送两个分组 -> 以此类推

什么是Nagle算法和TCP_NODELAY?

由于每个TCP段都会有40个字节的标记和首部无法省略,所以在发送频繁的小数据请求时,这40个多余的字节带来的性能问题就会变得严重。

Nagle算法试图在发送一个分组前,将大量的TCP数据绑定在一起,以提高网络效率。

仅适合频繁的小数据请求

缺点:可能会因为无法填满一个分组,导致一直等待永远不会到来的数据而产生延迟

什么是TIME_WAIT累积与端口耗尽?

在TCP关闭后,在内存中会维持一个小的控制块,用来记录最近这个关闭的IP地址和端口号,通常会存在一段时间,通常是所顾忌的最大分段试用期的两倍(2MSL,通常为两分钟),确保分组被复制且插入了具有相同连接值(源/目的IP地址和端口号),这样会破坏TCP数据。

TIME_WAIT

但是这种情况下有可能产生问题,原因是因为可用端口数是有限的,也就是假如可用端口是60000个,那么如果2MSL两分钟,则连接率不能高于 60000 / 120 = 500个/秒。

另外要注意大量打开连接或控制块的情况下,有些操作系统的速度会严重减缓。

从哪些方面来提升HTTP性能?

  • 并行连接
  • 持久连接
  • 管道化连接
  • 复用连接

并行连接有什么优点和限制?

并行连接不一定更快,但会让人“感觉上”更快,因为如果客户端的网络带宽较小时,大部分的时间其实是用来传输数据的,,如果此时一个连接就足以把带宽占满反倒并行连接会消耗很多内存资源,在效率上也没有什么提升,得不偿失。

一般浏览器把并行连接数限定在较小的值,通常是4个。

持久连接是什么?与并行连接相比有什么好处?

在HTTP/1.1协议中,支持HTTP设备在事物处理结束之后将TCP保持打开状态,以便之后的复用。

好处是既可以避免缓慢的连接建立,也就是三次握手阶段,还可以避免慢启动的拥塞适应阶段,以便更快速地进行数据传输。

Keep-Alive首部在哑代理中会出现什么问题?

会出现仅有第一个请求有效,其余请求都被代理忽略,从而导致客户端一直loading而得不到返回结果。

原因如下:

Keep-Alive

主要原因就是逐跳首部被哑代理当成了端到端首部进行传输。

什么是端到端首部?什么是逐跳首部?

  • 端到端首部(End-to-end Header)分在此类别中的首部会转发给请求/响应对应的最终接受目标,且必须保存在由缓存生成的响应中,另外规定它必须被转发。

  • 逐跳首部(Hop-by-hop Header)分在此类别中的首部只对单次转发有效,会因通过缓存或代理而不再转发。所有的Connection首部都是不能被转发的,例如Connection/Keep-Alive/Proxy-Authenticate/Proxy-Authorization/Trailer/TE/Transfer-Encoding/Upgrade

有什么办法可以解决Keep-Alive在哑代理的问题?

Netscape通过将Connection:Keep-Alive改成Proxy-Connectoion:Keep-Alive进行传输。由于Proxy-Connectoion:Keep-Alive是自定义的,服务器并不知道是什么意思,如果哑代理传输过去后,服务器当做普通连接进行处理,就不会出现代理收不到接下来的请求的问题了。

哑代理聪明代理解决方式

但这个方法只能在中间没有出现哑代理和聪明的代理结合的情况下才有效。

哑代理聪明代理混合

持久连接和keep-alive有什么不同?

keep-alive是HTTP/1.0+加入的首部字段,而持久连接是在HTTP/1.1就默认支持的,如果要在事务结束后关闭,就需要在报文里添加Connection:close首部。

持久连接和管道化连接有什么不同?

管道连接是在持久连接上,相对于keep-alive的又一个性能优化,在响应到达之前,可以将多条请求加入队列。当第一条请求通过网络流向服务器时,第二条和第三条请求也可以开始发送了。

具体区别:

三种连接的区别

什么是幂等事物,什么是非幂等事物?

如果一个事物,不管执行一次还是执行多次,得到的结果都是相同的,那么这个事物就是幂等的。比如:GET、HEAD、PUT、DELETE、TRACE和OPTIONS方法。

反之,非幂等事物的请求(比如POST),这种事物就不应该以管道化的方式传送非幂等请求,要发送一条非幂等请求,就需要等待来自前一条请求的响应状态。

怎么样的连接是正常关闭的?

完全关闭与半关闭有什么区别?

  1. 应用程序关闭TCP输入和输出信道中的任意一个,只有两者都关闭了,socket才会调用close()将TCP连接的输入和输出信道都关闭,此时才是完全关闭。
  2. 当socket调用shutdown()时,此时会单独关闭输入/输出信道,被称为“半关闭”。

半关闭状态,哪种情况更加危险?

关闭连接的输出信道是安全的,因为连接另一端的对等实体会从其缓冲区中读取所有数据之后收到一条通知,说明流结束了,这样你就知道将连接关闭了。

而关闭连接的输入信道是危险的,大部分操作系统会对这种情况视为很严重的错误来处理,比如:假设你在一条持久连接发送了10条管道式请求,此时数据还在应用缓冲区存着,此时第11条请求,服务器将连接关闭,而这条请求会发送到已经关闭的连接上去,并且会回送一条重置的信息,之前缓冲数据都会丢失。

输入输出信道

那么正确关闭HTTP请求连接顺序是什么样的?

正常关闭的应用程序首先应该关闭输出信道,然后等待连接另一端的实体关闭输入信道。