{{ v.name }}
{{ v.cls }}类
{{ v.price }} ¥{{ v.price }}
1、什么是keep-alive模式?
我们知道http协议采用“请求-应答”模式,当使用普通模式,即非keepalive模式时,每个请求/应答客户和服务器都要新建一个连接,完成之后立即断开连接(http协议为无连接的协议);当使用keep-alive模式(又称持久连接、连接重用)时,keep-alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,keep-alive功能避免了建立或者重新建立连接。
http1.0中默认是关闭的,需要在http头加入"connection:keep-alive",才能启用keep-alive;http1.1中默认启用keep-alive,如果加入"connection:close",才关闭。目前大部分浏览器都是用http1.1协议,也就是说默认都会发起keep-alive的连接请求了,所以是否能完成一个完整的keep-alive连接就看服务器设置情况。
2、启用keep-alive的优点
从上面的分析来看,启用keep-alive模式肯定更高效,性能更高。因为避免了建立/释放连接的开销。下面是rfc2616上的总结:byopeningandclosingfewertcpconnections,cputimeissavedinroutersandhosts(clients,servers,proxies,gateways,tunnels,orcaches),andmemoryusedfortcpprotocolcontrolblockscanbesavedinhosts.httprequestsandresponsescanbepipelinedonaconnection.pipeliningallowsaclienttomakemultiplerequestswithoutwaitingforeachresponse,allowingasingletcpconnectiontobeusedmuchmoreefficiently,withmuchlowerelapsedtime.networkcongestionisreducedbyreducingthenumberofpacketscausedbytcpopens,andbyallowingtcpsufficienttimetodeterminethecongestionstateofthenetwork.latencyonsubsequentrequestsisreducedsincethereisnotimespentintcp'sconnectionopeninghandshake.httpcanevolvemoregracefully,sinceerrorscanbereportedwithoutthepenaltyofclosingthetcpconnection.clientsusingfutureversionsofhttpmightoptimisticallytryanewfeature,butifcommunicatingwithanolderserver,retrywitholdsemanticsafteranerrorisreported.rfc2616(p47)还指出:单用户客户端与任何服务器或代理之间的连接数不应该超过2个。一个代理与其它服务器或代码之间应该使用不超过2*n的活跃并发连接。这是为了提高http响应时间,避免拥塞(冗余的连接并不能代码执行性能的提升)。
3、回到我们的问题(即如何判断消息内容/长度的大小?)
keep-alive模式,客户端如何判断请求所得到的响应数据已经接收完成(或者说如何知道服务器已经发生完了数据)?我们已经知道了,keep-alive模式发送玩数据http服务器不会自动断开连接,所有不能再使用返回eof(-1)来判断(当然你一定要这样使用也没有办法,可以想象那效率是何等的低)!下面我介绍两种来判断方法。3.1、使用消息首部字段conent-length
故名思意,conent-length表示实体内容长度,客户端(服务器)可以根据这个值来判断数据是否接收完成。但是如果消息中没有conent-length,那该如何来判断呢?又在什么情况下会没有conent-length呢?请继续往下看……
3.2、使用消息首部字段transfer-encoding
当客户端向服务器请求一个静态页面或者一张图片时,服务器可以很清楚的知道内容大小,然后通过content-length消息首部字段告诉客户端需要接收多少数据。但是如果是动态页面等时,服务器是不可能预先知道内容大小,这时就可以使用transfer-encoding:chunk模式来传输数据了。即如果要一边产生数据,一边发给客户端,服务器就需要使用"transfer-encoding:chunked"这样的方式来代替content-length。
chunk编码将数据分成一块一块的发生。chunked编码将使用若干个chunk串连而成,由一个标明长度为0的chunk标示结束。每个chunk分为头部和正文两部分,头部内容指定正文的字符总数(十六进制的数字)和数量单位(一般不写),正文部分就是指定长度的实际内容,两部分之间用回车换行(crlf)隔开。在最后一个长度为0的chunk中的内容是称为footer的内容,是一些附加的header信息(通常可以直接忽略)。chunk编码的格式如下:
复制代码代码如下:
chunked-body=*chunk"0"crlffootercrlfchunk=chunk-size[chunk-ext]crlfchunk-datacrlf
hex-no-zero=<hexexcluding"0">
chunk-size=hex-no-zero*hexchunk-ext=*(";"chunk-ext-name["="chunk-ext-value])chunk-ext-name=tokenchunk-ext-val=token|quoted-stringchunk-data=chunk-size(octet)
footer=*entity-header
即chunk编码由四部分组成:1、0至多个chunk块,2、"0"crlf,3、footer,4、crlf.而每个chunk块由:chunk-size、chunk-ext(可选)、crlf、chunk-data、crlf组成。4、消息长度的总结
其实,上面2中方法都可以归纳为是如何判断http消息的大小、消息的数量。rfc2616对消息的长度总结如下:一个消息的transfer-length(传输长度)是指消息中的message-body(消息体)的长度。当应用了transfer-coding(传输编码),每个消息中的message-body(消息体)的长度(transfer-length)由以下几种情况决定(优先级由高到低):任何不含有消息体的消息(如1xxx、204、304等响应消息和任何头(head,首部)请求的响应消息),总是由一个空行(clrf)结束。如果出现了transfer-encoding头字段并且值为非“identity”,那么transfer-length由“chunked”传输编码定义,除非消息由于关闭连接而终止。如果出现了content-length头字段,它的值表示entity-length(实体长度)和transfer-length(传输长度)。如果这两个长度的大小不一样(i.e.设置了transfer-encoding头字段),那么将不能发送content-length头字段。并且如果同时收到了transfer-encoding字段和content-length头字段,那么必须忽略content-length字段。如果消息使用媒体类型“multipart/byteranges”,并且transfer-length没有另外指定,那么这种自定界(self-delimiting)媒体类型定义transfer-length。除非发送者知道接收者能够解析该类型,否则不能使用该类型。由服务器关闭连接确定消息长度。(注意:关闭连接不能用于确定请求消息的结束,因为服务器不能再发响应消息给客户端了。)为了兼容http/1.0应用程序,http/1.1的请求消息体中必须包含一个合法的content-length头字段,除非知道服务器兼容http/1.1。一个请求包含消息体,并且content-length字段没有给定,如果不能判断消息的长度,服务器应该用用400(badrequest)来响应;或者服务器坚持希望收到一个合法的content-length字段,用411(lengthrequired)来响应。
所有http/1.1的接收者应用程序必须接受“chunked”transfer-coding(传输编码),因此当不能事先知道消息的长度,允许使用这种机制来传输消息。消息不应该够同时包含content-length头字段和non-identitytransfer-coding。如果一个消息同时包含non-identitytransfer-coding和content-length,必须忽略content-length。
5、http头字段总结