一,持久连接
什么是持久连接?对于HTTP协议而言,它是基于请求响应模型,Client向Server发请求时,先建立一条HTTP连接,Server给Client响应数据后,连接关闭。
当Client发送下一个请求时,需要重新再建立HTTP连接,这种方式就是:一个请求响应需要占用一条HTTP连接。而持久连接就是:只需要建立一条连接,然后在这条连接上 传输多个请求和响应。
与持久连接相关的字段
HTTP1.0中有一个Connection首部字段,它是一个逐跳首部字段。Connection:Keep-Alive,表示希望将此条连接作为持久连接。
HTTP1.1中,建立的HTTP请求默认是持久连接的。当Client确定不再需要向Server发送数据时,它可以关闭连接,即在发送首部中添加Connection:Closed字段。
二,如何提高HTTP请求的处理速度
①并行连接
Client一次向Server请求建立多个HTTP连接,每个HTTP连接上发一个请求,这样就可以并行地发多个请求获取响应数据。
比如,访问某个web页面,它上面有4幅图片,这些图片存储在不同的服务器上。那可以同时向服务器发4个HTTP请求去获取这四幅图片,而不是串行地依次发HTTP请求先获得第一幅图片,然后再发第二个HTTP请求获得第二幅图片....
并行连接,显然增加了服务器端的压力,要求服务器能够承载大量的HTTP请求。
②持久连接
持久连接的一个最大的好处是:大大减少了连接的建立以及关闭时延。
HTTP连接是建立在TCP协议之上的,建立一条TCP连接需要三次握手,TCP连接关闭时需要四次挥手。这些都是需要时间的。
而在第一点中提到:持久连接就是:只需要建立一条连接,然后在这条连接上 传输多个请求和响应。那么,就不需要频繁地建立连接,当前也就消除了连接建立以及关闭的时延了。
如图:多个请求响应在一条连接内完成了。但是,这里也看出一个“缺点”,请求响应是顺序执行的。只有在请求1的响应收到之后,才会发送请求2,这就是持久连接与管道化连接不同的地方。
③管道化连接
什么是管道化连接?
显然,管道化连接是需要持久连接支持的。管道化连接是在持久连接的基础上,以“流水线”的方式发送请求:不需要等到请求1的响应到达Client,就可以发送请求2....
HTTP连接如何正确地关闭?
HTTP连接的关闭需要注意这两个问题:HTTP连接是双向的;HTTP请求的幂等性。
连接是双向的
TCP连接是双向的,TCP连接的发送端和接收端都分别有:发送缓冲区和接收缓冲区,它们对应着输出信道和输入信道。
在JAVA中,JDK类库 java.net.Socket 类的 close()方法会关闭整个TCP连接,即输入信道和输出信道都被关闭了。
另外,Socket类还提供了两个方法:shutdownInput() 和 shutdownOutput(),前者用来关闭输入信道,后者用来关闭输出信道。
若只关闭其中TCP连接中的一条信道,则称之为半关闭。
一般而言,关闭连接的输出信道总是安全的。当你确定 以后都没有数据要发送到对方时,你可以把你的输出信道关闭了。
关闭输入信道有风险,可能会导致:连接被对端重置。
比如,在 服务器刚好把输入信道关闭时,客户端向服务器发起了请求,那此时客户端就会收到一条“连接被重置”的报文。在这种情况下,客户端的操作系统就会把客户端中的接收缓冲区里面的数据都清空。如果,此时客户端的应用程序还未来得及从接收缓冲区中取走数据,那么以前发送请求获得的数据也都被清空了!
因此, 正确的关闭HTTP连接的方式是:(以Client的视角来描述)
Client先关闭自己的输出信道(Client不能把自己的输入信道关闭了)。
然后Client周期性地轮询自己的输入信道的状态(比如,读取数据时,是不是 已经读到的 流的结尾了),如果读到了 流的结束标识符,那意味着Server发过来的数据都已经收到了。
总之,对于HTTP连接的双方而言,当不再需要传输数据时,双方都先把自己的输出信道关闭了,然后读取输入信道中的流,如果读到了末尾(比如流结束符返回-1),那么就可以正常关闭HTTP连接了。
参考资料:
《HTTP权威指南》第四章
《图解HTTP》