HTTP之持久连接
HTTP/1.1 允许 HTTP 设备在事务处理结束之后将 TCP 连接保持在打开状态,以便为未来的 HTTP 请求重用现存的连接。在事务处理结束后仍然保持在打开状态的 TCP 连接被称为持久连接。非持久连接会在每个事务结束之后关闭。持久连接会在不同事务之间保持打开状态,直到客户端或服务器决定将其关闭为止。
持久连接降低时延和连接建立的开销,将连接保持在已调谐状态,而且减少了打开连接的潜在数量。
持久连接与并行连接配合使用可能是最高效的方式。持久连接有两种类型:比较老的 HTTP/1.0+ "keep-alive" 连接,以及现代的 HTTP/1.1 "persistent" 连接。
Keep-Alive 操作
实现 HTTP/1.0 keep-alive 连接的客户端可以通过包含 Connection: Keep-Alive 首部请求将一条连接保持在打开状态。
如果服务器愿意为下一条请求将连接保持在打开状态,就在响应中包含相同的首部。如果响应中没有 Connection: Keep-Alive 首部,客户端就认为服务器不支持 keep-alive,会在发回响应报文之后关闭连接。
Keep-Alive 选项
Keep-Alive 首部只是请求将连接保持在活跃状态。发出 keep-alive 请求之后,客户端和服务器并不一定会同意进行 keep-alive 会话。它们可以在任意时刻关闭空闲的 keep-alive 连接,并可随意限制 keep-alive 连接所处理事务的数量。
可以用 Keep-Alive 通用首部中指定的、由逗号分隔的选项来调节 keep-alive 的行为:
- 参数 timeout 是在 Keep-Alive 响应首部发送的。它估计了服务器希望将连接保持在活跃状态的时间。这并不是一个承若值。
- 参数 max 是在 Keep-Alive 响应首部发送的。它估计了服务器还希望为多少个事务保持此连接的活跃状态。这并不是一个承若值。
- Keep-Alive 首部还可支持未经处理的属性,这些属性主要用于诊断和调试。语法为 name [=value]。
Keep-Alive 首部完全是可选的,但只有在提供 Connection: Keep-Alive 时才能使用它。下面示例的 Keep-Alive 说明服务器最多还会为另外 5 个事务保持连接的打开状态,或者将打开状态保持到连接空闲了 2 分钟之后。
Connection: Keep-Alive
Keep-Alive: max=5, timeout=120
Keep-Alive 连接的限制和规则
- 在 HTTP/1.0 中,keep-alive 并不是默认使用的。客户端必须发送一个 Connection: Keep-Alive 请求首部来激活 keep-alive 连接。
- Connection: Keep-Alive 首部必须随所有希望保持持久连接的报文一起发送。如果客户端没有发送 Connection: Keep-Alive 首部,服务器就会在那条请求之后关闭连接。
- 客户端探明响应中没有 Connection: Keep-Alive 响应首部,就可以知道服务器发出响应之后是否会关闭连接了。
- 只有在无需检测到连接的关闭即可确定报文实体主体部分长度的情况下,才能将连接保持在打开状态--也就是说实体的主体部分还必须有正确的 Content-Length,有多部件媒体类型,或者用分块传输编码的方式进行了编码。在 keep-alive 信道中回送错误的 Content-Length 是很糟糕的事,这样事务处理的另一端就无法精确地检测到一条报文的结束和另一条报文的开始了。
- 代理和网关必须执行 Connection 首部的规则。代理或网关必须在将报文转发出去或将其高速缓存之前,删除在 Connection 首部中命名的所有首部字段以及 Connection 首部自身。
- 不应该与无法确定是否支持 Connection 首部的代理服务器建立 keep-alive 连接,以防止出现下面的哑代理问题。但在实际应用中不是总能做到这一点。
- 从技术上讲,应该忽略所有来自 HTTP/1.0 设备的 Connection 首部字段(包括 Connection: Keep-Alive),因为它们可能是由比较老的代理服务器误转发的。
- 除非重复发送请求会产生其他一些副作用,否则如果在客户端收到完整响应之前连接就关闭了,客户端就一定要做好重试请求的准备。
Keep-Alive 和哑代理
1. Connection 首部和盲中继
问题出在代理上--尤其是那些不理解 Connection 首部,而且不知道在沿着转发链路将其发送出去之前,应该将该首部删除的代理。很多老的或简单的代理都是盲中继(blind relay),它们只是将字节从一个连接转发到另一个连接中去,不对 Connection 首部进行特殊的处理。
- Web 向代理发送包含 Connection: Keep-Alive 首部的报文,期待建立一个 keep-alive 连接;
- 哑代理收到这条请求,但并不理解 Connection 首部(只是将其作为一个扩展首部对待)。因此只是沿着转发链路将报文一字不漏地发送给服务器。但 Connection 首部是个逐跳首部,只适用于单条传输链路,不应该沿着传输链路向下传输。
- 经过中继的 HTTP 请求到达 Web 服务器。当 Web 服务器收到经过代理转发的 Connection: Keep-Alive 首部时,会误以为代理希望进行 keep-alive 对话,因此回送一个 Connection: Keep-Alive 响应首部。所以,此时 Web 服务器认为它在与代理进行 keep-alive 对话,会遵循 keep-alive 规则。但代理却对 keep-alive 一无所知。
- 哑代理将 web 服务器的响应报文回送给客户端,并将来自 web 服务器的 Connection: Keep-Alive 首部一起传送过去。客户端看到这个首部,会认为代理同意进行 keep-alive 对话。所以,此时客户端和服务器都认为它们在进行 keep-alive 对话,但与它们进行对话的代理却对 keep-alive 一无所知。
- 由于代理不知道 keep-alive,所以会将收到的所有数据都回送给客户端,然后等待源端服务器关闭连接。但源端服务器会认为代理已经显式地请求它将连接保持在打开状态了,所以不会去关闭连接。这样,代理就会挂在那里等待连接的关闭。
- 客户端收到回送的响应报文时,会立即转向下一条请求,在 keep-alive 连接上向代理发送另一条请求。而代理并不认为同一条请求上会有其他请求到来,请求被忽略,浏览器就挂在那里了。
- 这种错误的通信方式会使浏览器一直处于挂起状态,直到客户端或服务器将来连接超时,并将其关闭为止。
代理和逐跳首部
为避免这类代理通信问题的发生,现代的代理都绝不能转发 Connection 首部和所有名字出现在 Connection 值中的首部。因此,如果一个代理收到了一个 Connection: Keep-Alive 首部,是不应该转发 Connection 首部,或所有名为 Keep-Alive 首部的。
如下几个首部不能作为 Connection 首部值列出,也不能被代理转发或作为缓存相应使用的首部:Proxy-Authenticate、Proxy-Connection、Transfer-Encoding 和 Upgrade。
插入 Proxy-Connection
对盲中继的变通做法是引入了一个名为 Proxy-Connection 的新首部,解决了在客户端后面紧跟着一个盲中继所带来的问题--但并没有解决所有其他情况下存在的问题。
浏览器会向代理发送非标准的 Proxy-Connection 扩展首部,而不是官方支持的著名的 Connection 首部。如果代理是盲中继,它会将无意义的 Proxy-Connection 首部转发给 Web 服务器,服务器会忽略此首部,不会带来任何问题。但如果是能够理解持久连接的代理,就用一个 Connection 首部取代无意义的 Proxy-Connection 首部,然后将其发送给服务器。
Proxy-Connection 首部修正了单个盲中继带来的问题:
对有多层次代理的情况,Proxy-Connection 仍然无法解决问题:
HTTP/1.1 持久连接
HTTP/1.1 逐渐停止了对 keep-alive 连接的支持,用一种名为持久连接(persistent connection)的改进型设计取代了它。
HTTP/1.1 持久连接在默认情况下是激活的。除非特别指明,否则 HTTP/1.1 假定所有连接都是持久的。要在事务处理结束之后将连接关闭,HTTP/1.1 应用程序必须向报文中显式地添加一个 Connection: close 首部。但是,客户端和服务器仍然可以随时关闭空闲的连接。不发送 Connection: close 并不意味着服务器承若永远将连接保持在打开状态。
持久连接的限制和规则
- 发送了 Connection: close 请求首部之后,客户端就无法在那条连接上发送更多的请求了。
- 如果客户端不想在连接上发送其他请求了,就应该在最后一条请求中发送一个 Connection: close 请求首部。
- 只有当连接上所有的保卫都有正确的、自定义报文长度时--也就是说,实体主体部分的长度都和相应的 Connection-Length 一致,或者是用分块传输编码方式编码的--连接才能持久连接。
- HTTP/1.1 的代理必须能够分别管理与客户端和服务器的持久连接--每个持久连接都只适用于一跳传输。
- HTTP/1.1 的代理服务器不应该与 HTTP/1.O 客户端建立持久连接,除非它们了解客户端的处理能力。
HTTP之持久连接的更多相关文章
- asp.net signalR 专题—— 第二篇 对PersistentConnection持久连接的快速讲解
上一篇我们快速的搭建了一个小案例,但是并没有对其中的方法进行介绍,这一篇我来逐一解析下. 一:从override的那些方法说起 不管怎么样,我们先上代码,如下: public class MyConn ...
- LVS持久连接
LVS持久连接 源地址HASH ipvs的连接模板 可以通过ipvsadm -L -c 持久连接持久客户端连接 PCC:在固定时间内将来自于同一个客户端发往VIP的所有请求统统定向至同一个RS0表示所 ...
- php开发客服系统(持久连接+轮询+反向ajax 转载 http://www.tuicool.com/articles/2mU7v2R)
php开发客服系统( 下载源码 ) 用户端(可直接给客户发送消息) 客服端(点击用户名.即可给该用户回复消息) 讲两种实现方式: 一:iframe + 服务器推技术comet(反向ajax,即服务器向 ...
- WebSocket 是什么原理?为什么可以实现持久连接?
https://www.zhihu.com/question/20215561 作者:Ovear链接:https://www.zhihu.com/question/20215561/answer/ ...
- HTTP - 持久连接
Web 客户端经常会打开到同一个站点的连接.比如,一个 Web 页面上的大部分内嵌图片通常都是来自同一个 Web 站点,而且相当一部分指向其他对象的超链接通常都指向同一个站点.因此,初始化了对某服务器 ...
- ASP.NET SignalR2持久连接层解析
越是到年底越是感觉浑身无力,看着啥也不想动,只期盼着年终奖的到来以此来给自己打一针强心剂.估摸着大多数人都跟我一样犯着这样浑身无力的病,感觉今年算是没挣到啥钱,但是话也不能这么说,搞得好像去年挣到钱了 ...
- php开发客服系统(持久连接+轮询+反向ajax)
欢迎在php严程序 - php教程学习AJAX教程, 本节课讲解:php开发客服系统(持久连接+轮询+反向ajax) php开发客服系统(下载源码) 用户端(可直接给客户发送消息)客服端(点击用户名. ...
- HTTP实现长连接(TTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持Connection: keep-alive)
HTTP实现长连接 HTTP是无状态的 也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接.如果客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web ...
- HTTP协议----URI,URL,持久连接,管道与Cookie
URI与URL有什么不同呢? URI:Universal Resource Identifier统一资源标志符 URL:Universal Resource Locator统一资源定位器 URI是用来 ...
- Http持久连接与HttpClient连接池
一.背景 HTTP协议是无状态的协议,即每一次请求都是互相独立的.因此它的最初实现是,每一个http请求都会打开一个tcp socket连接,当交互完毕后会关闭这个连接. HTTP协议是全双工的协议, ...
随机推荐
- GIL锁、进程池与线程池、同步异步
GIL锁定义 GIL锁:Global Interpreter Lock 全局解释器 本质上是一把互斥锁 官方解释: 在CPython中,这个全局解释器锁,也称为GIL,是一个互斥锁,防止多个线程在同 ...
- [Vuex系列] - Actions的理解之我见
Actions如何定义的 恕小端不才,对Action的总结如下: Action 可以提交mutation方法,通过mutation来改变state Action 函数可以接收一个context对象,通 ...
- nginx 反向代理的配置
nginx中的每个server就是一个反向代理配置,可以有多个server(nginx只能处理静态资源) nginx中 server的配置 server { listen 80; server_nam ...
- 二〇一八-网易秋招面试解析(Java)
一轮面试: Java内存模型讲一下 GC算法,知道的都讲一下 HashMap,get,put实现 JsonWebToken具体实现流程(简历) Spring AOP如何实现,写一个AOP功能的主要流程 ...
- 更优雅地关闭资源 - try-with-resource及其异常抑制--转载
原文地址:https://www.cnblogs.com/itZhy/p/7636615.html 一.背景 我们知道,在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必 ...
- Ubuntu 手动挂载exfat格式的U盘
1.默认Ubuntu不支持exFat格式的U盘,先要安装支持: sudo apt-get install exfat-fuse 2.挂载磁盘,我选择挂在mnt下面 a.创建挂载目录:sudo mkdi ...
- 内核对象&句柄
目录 1 内核对象的概念 2 内核对象的使用计数 3 句柄 4 句柄表 项目工程代码中设计句柄的使用,一时不知句柄是何物,通过查阅自学之后,对句柄及其使用有一个初步的了解.分享出来,算是抛砖引玉吧 ...
- Centos 升级至 OpenSSH 8 rpm包制作
背景 安全部门扫描系统漏洞,OpenSSH 7.9出现漏洞,需升级到8. 使用 rpmbuild 将源码包编译为 rpm包. yum install rpm-build zlib-devel open ...
- 0001SpringBoot整合Mybatis
SpringBoot整合Mybatis主要分为以下几个步骤: 1.添加Mybatis的起步依赖(pom.xml) 2.添加数据库驱动坐标(pom.xml) 3.添加数据库连接信息(applicatio ...
- C语言博客I作业04
问题 回答 这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 作业要求 我在这个课程的目标是 掌握使用for循环语句实现指定次数的循环程序设计. 这个作业在那个具体方面帮助我实现目标 通过 ...