夭幻境地

关注技术,关心成长,关怀世事人情

HTTP之多事务的连接方式

HTTP是一个应用层协议,基于TCP/IP。HTTP的连接其实就是TCP连接,从头到尾都是。只不过在其中传递的数据包不是任意的二进制,而是HTTP规定好的数据包。数据的发送也不是任意的,而是一个请求一个响应(请求和响应一对构成一个事务)。

我们关心连接的使用方式,是因为它事关多事务情况下的性能。而在http中,处理多事务的连接有4种方式:

  • 并行连接
  • Keep-Alive
  • 持久连接
  • 管线(pipeline)。

我们拿一个简单的文件作为多事务的案例(文件名为1.html):

<html>
<body>
  <h1>image/<h1>
  <img src="2.png"/>
  <img src="3.png"/>
</body>
</html>  

即使如此简单的HTML文件,完全获取资源并呈现给客户也需要三个事务。这三个事务分别用来获取1.html、2.png、3.png文件。我们来看不同的事务处理模型应对此组请求有何不同。

并行连接

我们首先访问1.HTML,那么客户端会发送1个请求给服务器。首先获取1.html,是“打开连接、发送请求、获取响应、关闭”。

GET /1.HTML 

然后获取2.png,依然是“打开连接、发送请求、获取响应、关闭”。

GET /2.png

然后获取3.png,依然是“打开连接、发送请求、获取响应、关闭”。

GET /3.png

这样,为了获取3个文件,我们做了三次重复的连接打开和关闭过程。因为获取了1.html ,解析知道1.png和 2.png文件,之后可以不必分次序,而是同时打开两个连接,分别同时获取2个png资源,然后关闭。

然而,既然三个资源都在同一个服务器,请求也都来自一个客户端,是否可以重用既有的已经打开的连接呢?这样做是允许的,接下来的两种连接模型都是出于这样的优化目的而设计出来的。

keep-alive连接

keep-alive方法允许客户端和服务器暂时不关闭连接而继续用于接下来的事务。HTTP协议引入了Connection:keep-alive的首部字段,让双方都可以表达保持连接打开的意图。这样,上面的3个事务就变成了:

打开连接、发送请求、获取响应、但是不关闭:

GET /1.HTML 
Connection:keep-alive

---------

HTTP/1.1 200 OK
Connection:keep-alive

内容...

然后获取2.png,“使用现有连接、发送请求、获取响应、也不关闭”。

GET /2.png
Connection:keep-alive

---------
HTTP/1.1 200 OK
Connection:keep-alive

内容...

然后获取3.png,依然是“使用现有连接、发送请求、获取响应、关闭”。

GET /3.png
---------

HTTP/1.1 200 OK

内容...

最后一条事务没有发送Connection:keep-alive,因此连接关闭。

使用keep-alive之后,效果就是后面的两个事务可以重用第一个事务建立的连接,从而省下两次打开和关闭连接的开销。

持久连接

持久连接是对 keep-alive 的改进。持久连接通过头字段值Connection:close 来通知连接关闭,如果没有发送,就表示保持打开。和 keep-alive 的差别在于默认值的不同,持续连接默认保持,而Keep-Alive默认关闭。这就是两者的不同。再看同样的案例,在持久连接下的不同表现:

打开连接、发送请求、获取响应、但是不关闭:

GET /1.HTML 
---------

HTTP/1.1 200 OK

内容...

然后获取2.png,“使用现有连接、发送请求、获取响应、也不关闭”:

GET /2.png

---------
HTTP/1.1 200 OK

内容...

然后获取3.png,依然是“使用现有连接、发送请求、获取响应、关闭”:

GET /3.png
Connection:close
---------

HTTP/1.1 200 OK
Connection:close
内容...

持久连接和Keep-alive在重用连接方面是一致的。但是使用持久连接可以少发送两次Connection头字段。

管线

管线是在持久连接的基础上的又一次优化。持久连接内的事务还是逐个方式的。就是说,客户端发起一个请求,然后等待响应,响应收完了再发新的请求。而管线的做法是不同的,在这个模型下,客户端可以一次发出全部请求,然后按照发出的次序,逐个的收对应的响应。依然看案例:

首先获取1.html,打开连接、发送请求、获取响应、但是不关闭:

GET /1.HTML 
---------

HTTP/1.1 200 OK

内容...

然后解析完成1.html,浏览器发现要完整呈现还需要两个资源:2.png和3.png。这时就和前面的事务模型有体现出差别了:客户端会同时在同一连接内发出两个GET请求,而服务器会按照请求的次序,发送两个响应回来。

GET /2.png

GET /3.png
Connection:close
---------
HTTP/1.1 200 OK

内容...

HTTP/1.1 200 OK
Connection:close

内容...

这就是管线模式和持久连接的不同。在高时延网络条件下,这样做可以降低网络时间。

嗯,这就是4种处理多事务的连接模型的差别。


本文参考自:《HTTP小书》(刘传君)