什么是Http长连接
长连接定义:
client方与server方先建立连接,连接建立后不断开,然后再进行报文发送和接收。这种方式下由于通讯连接一直存在。此种方式常用于P2P点对点的通信。
长连接的操作步骤是:建立连接——数据传输...(保持连接)...数据传输——关闭连接
长连接适用场景:
监控系统:后台硬件热插拔、LED、温度、电压发生变化;
即时通信系统:其它用户登录、发送信息;
即时报价系统:后台数据库内容发生变化;
像以上这些连接,如果每次操作都要建立连接然后再操作的话处理速度会降低。所以操作时第一次连接上以后,以后每次直接发送数据就可以了,不用再建立TCP连接。
再比如:数据库的连接用长连接,如果用短连接频繁的通信会造成socket错误,频繁的socket创建也是对资源的浪费。
Comet
以前的http的长连接技术不成熟,目前有新技术名叫Comet:基于 HTTP 长连接的“服务器推”技术。
案例:基于 AJAX 的长轮询(long-polling)方式
AJAX 的出现使得 JavaScript 可以调用 XMLHttpRequest 对象发出 HTTP 请求,JavaScript 响应处理函数根据服务器返回的信息对 HTML 页面的显示进行更新。使用 AJAX 实现“服务器推”与传统的 AJAX 应用不同之处在于执行顺序及内容:
1.服务器端会阻塞请求直到有数据传递或超时才返回。
2.客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
3.当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重新建立连接,客户端会一次把当前服务器端所有的信息取回。
具体方案及案例可以参考IBM官网:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/
什么是Http短连接
短连接定义
Client方与server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。此方式常用于一点对多点通讯。
短连接的操作步骤是:建立连接——数据传输——关闭连接...建立连接——数据传输——关闭连接
短连接的适用场景:
短连接多用于操作频繁,点对点的通讯,而且连接数不能太多的情况。每个TCP连接的建立都需要三次握手,每个TCP连接的断开要四次握手。
web网站的http服务一般都用短连接。因为长连接对于服务器来说要耗费一定的资源。像web网站这么频繁的成千上万甚至上亿客户端的连接用短连接更省一些资源。
试想如果都用长连接,而且同时用成千上万的用户,每个用户都占有一个连接的话,可想而知服务器的压力有多大。所以并发量大,但是每个用户又不需频繁操作的情况下需要短连接。总之:长连接和短连接的选择要视需求而定。
什么是Http持久连接
HTTP协议是位于传输层之上的应用层协议,其网络层基础通常是TCP协议。TCP协议是面向连接和流的,因此连接的状态和控制对于HTTP协议而言相当重要。同时,HTTP是基于报文的,因此如何确定报文长度也是协议中比较重要的一点。
Persistent Connections持久连接
在使用持久连接前,HTTP协议规定为获取每个URL资源都需要使用单独的一个TCP连接,这增加了HTTP服务端的负载,引起互联网拥塞。例如内嵌图片以及其他类似数据的使用要求一个客户端在很短时间内向同一个服务端发起多个请求。
使用持久连接的优点:
减少TCP连接数量
在一个连接上实现HTTP请求和应答的流水,即允许客户端发出多个请求,而不必在接收到前一请求的应答后才发出下一请求,极大减少时间消耗
后续请求延迟减少,无需再在TCP握手上耗时
可以更加优雅地实现HTTP协议,由于持续连接的存在无需报告错误后无需关闭连接,因此客户端可使用最新的协议特性发出请求,如果接收到表示错误的应答,则换用更旧的语义。
总体描述
HTTP/1.1和之前版本的显著区别是HTTP/1.1默认使用持久连接。即,除非服务端在应答中明确指出,客户端应当假定服务端会维持一个持久连接,即使从服务端收到的应答是报告错误。
持久连接对关闭TCP连接的行为提供信号量机制支持。这个信号量是在HTTP头中的Connection域设置,注意Client向Proxy发出请求时该域可能被Proxy-Connection域替换。一旦close信号被表明,客户端绝不能再通过该连接发送更多的请求。
协商(Negotiation)
HTTP/1.1 服务端可以假定HTTP/1.1客户端会维持持久连接,除非请求中Connection域的值是"close".同样的,如果服务端打算在送出应答后立即关闭连接,它应当在应答中包含同样的Connection域。(TCP连接关闭是双向的,此时TCP进入半关闭状态)
同样的,HTTP/1.1客户端可以期望连接是持久的,除非如前所述收到表示连接关闭的应答。当然,也可以主动发出一个包含Connection:close的请求以表明终止连接。
无论客户端还是服务端发出的报文包含Connection:close,则该请求均为连接上的最后一个请求(服务端发出此应答后关闭,因此不可能接收更多的请求)
报文传输长度
为保证持久性,连接上的报文都必须有一个自定义的报文传输长度(否则必须通过连接的关闭表示报文结束,因为TCP连接是面向流的),确定的规则按优先级由高到低排列如下:
报文传输长度指报文中出现的报文体的长度(即,不包括头长度,因为报文头的结束可通过连续两个CRLF确定)
1.任何绝不能包含报文体(如1xx,204,304)的应答消息总是以头域后的第一个空行结束,无视头中所有的entity类型域的设置,包括Content-Length域。
2.Transfer-Encoding域出现,其值为除"identify"以外的其他值,则用"chunked"传输编码方式确定传输长度,具体方式留待下篇分析。
3.Content -Length域出现,且Transfer-Encoding域未出现(出现则忽略Content-Length域)。Content-Length域的值为十进制数的字节序,如Content-Length:1234,则1、2、3、4是分别作为一个octet传输的,因此需要atoi转换成数值。
4.如果报文使用了"multipart/byteranges"的媒体类型,且没对传输长度做前面的指明,则这种自分割的媒体类型定义了传输长度。具体参见Range头域的说明。
5.服务端关闭连接(此方法不可用于客户端发出的请求报文,因为客户端关闭连接则使得服务端无法发送应答).
为保持和HTTP/1.0的兼容性, 包含报文体的HTTP/1.1请求必须包含合法的Content-Length头域,除非明确知道服务端是HTTP/1.1兼容的.如果请求包含消息体, 而没有Content-Length域,那么如果服务端无法确定消息长度时,它会返回400(无效请求),或者坚持获取合法Content-Length 而返回411(要求包含长度).
所有接收实体的HTTP/1.1应用程序必须接受"chunked"传输编码, 这样允许当报文长度无法预先确定时可以运用此机制获取报文长度.
报文不能同时包含Content-Length头域和非"identity" Transfer-Encoding.如果出现了, Content-Length域必须被忽略.
当Content-Length域在允许报文体的报文中存在时, 其域值必须严格等于消息体中的8比特字节.HTTP/1.1 user agent 必须在接收并检测到一个错误的长度时提醒用户.
以上方法中,最常见的还是使用Content-Length域表示报文体长度,Transfer-Encoding需要按格式解码才能还原出发送编码前的报文。
流水
支持持久连接的客户端可以流水发送请求,服务端必须按发送的顺序发送应答。
假定持久连接和连接后即可流水的客户端应当做好在第一次流水失败后重新尝试此连接。在这样的尝试中,在确定连接是持久的之前,客户端不能再流水。
客户端同样必须准备好在服务端送回所有相关应答前就关闭连接时重发请求。
不应流水non-idempotent方法
Proxy Servers
对于代理服务端而言,正确实现Connection头域指定的属性尤为重要。
代理服务端必须分立通告它的客户端和连接的原始服务端持久连接的属性,每个持久连接设置仅针对一个传输连接。
实践考量
超时值,服务端通常会为每个连接维护一个定时器,一旦某个连接不活跃超过一定时间值,服务端会关闭此连接。考虑到一个客户端可能通过代理服务端发出更多连接,代理服务端通常会将超时值设置得更高。
还有一些关于从异步关闭中恢复的讨论。
报文传输要求
使用TCP流控制来解决服务端临时负载过高问题,而不是简单的依赖客户端重连而关闭连接。
监视连接情况以获取错误状态消息
关于使用100(继续)状态码
100状态码用于客户端发送请求体之前测试是否可以发送该请求,对于Proxy,有以下要求:
1.如果代理服务端接收到包含Expect头域值为"100-continue"的请求, 而不明确知道下一跳服务不支持HTTP/1.1以上版本, 则它必须转发这个请求, 包括Expect头域.
2.如果代理知道下一跳服务端为HTTP/1.0或者更低版本, 则它不能转发此请求, 且必须以407应答客户端.
3.如果明确知道发出请求的客户端版本为HTTP/1.0或者更低,则代理服务端绝不能转发100应答,这条规则凌驾于转发1xx应答的一般准则.
Connection头域说明
BNF文法:
Connection = "Connection" ":" 1#(connection-token)
connection-token = token
Connection头域中的token用于指定对于特定连接有意义的选项,因此proxy在转发前要扫描此域,从头中去除和token同名的域。例如Connection:Range,则要去掉Range域。
HTTP/1.1定义了close这个token,发送者用此token表示在完成这个报文所属请求/应答的收发后连接将关闭。