HTTP权威指南-连接管理
现在已经开始学习到第四章咯,坚持就是胜利哟~!ok,废话少说,继续写笔记。
本章中我们要介绍到HTTP的连接。好,现在有几个问题,我列出来了,带着这几个问题,我们进入本章的学习。
1.HTTP是如何使用TCP连接的;
2.TCP连接的时延、瓶颈以及存在的障碍;
3.HTTP的优化,包括并行连接、keep-alive(持久连接)和管道化连接;
4.管理连接时应该以及不应该做的事情。
首先,我们需要知道的是HTTP连接时HTTP报文传输的关键通道。
接下来我们来介绍关于TCP 的知识。
一、TCP连接
TCP/IP 是全球计算机及网络设备都在使用的一种常用的分组交换网络分层协议集。
当你点开客户端应用程序点击一条连接时。它会执行如下步骤:
浏览器解析出主机名->>查询主机名的IP地址->>浏览器获得端口号->>发起到此IP地址下端口号的连接->>浏览器向服务器发送一条HTTP GET的报文(请求报文)->>浏览器从服务器读取HTTP响应报文->>浏览器关系连接
1.TCP的可靠数据管道
TCP为HTTP提供一条可靠的比特传输管道。从TCP连接一端填入的字节会比另一端以原有的顺序正确地传送出来。
2.TCP流是分段的、由IP分组传送
TCP数据是通过名为IP分组(或IP数据报)的小数据块来发送的。
协议栈(协议栈是指网络中各层协议的总和,其形象的反映了一个网络中文件传输的过程:由上层协议到底层协议,再由底层协议到上层协议。使用最广泛的是因特网协议栈。)
HTTP:HTTP(应用层)->>TCP(传输层)->>IP(网络层)->>网络接口(数据链路层)
HTTPS(安全版本):HTTP(应用层)->>TSL or SSL(安全层)->>TCP(传输层)->>IP(网络层)->>网络接口(数据链路层)
TCP收到来自HTTP的数据流报文之后,会将数据流砍成被称作段的小数据块,并将段封装在IP分组中,通过因特网进行传输。
3.保持TCP连接持续不断地运行
TCP是通过端口号来保持所有这些链接持续不断地运行
TCP是通过4个值来识别的:<源IP地址、源端口号、目的IP地址、目的端口号>
两条不同的TCP链接不能拥有4个完全相同的地址组件值(但不同连接的部分组件可以拥有相同的值)
4.用TCP套接字编程
是用主机本地应用程序所创建的,应用程序通过这个接口,使用传输层提供的服务跨网络发送给其他应用程序。
三、HTTP连接的处理
1.常被误解的Connection首部
HTTP允许在客户端和最终的源端服务器之间存在一串HTTP中间实体(代理、高速缓存等)。
Connection首部可以承载3种不同类型的标签:HTTP首部字段名,任意标签值,值close
2.串行事务处理延时
几种方法提高HTTP的连接性能。
并行连接:通过多条TCP连接发起并发的HTTP请求
持久连接:重用TCP连接,以消除连接及关闭时延
管道化连接:通过共享的TCP连接发起并发的HTTP请求
复用的连接:交替传送请求和响应报文
四、并行连接
HTTP允许客户端打开多条连接,并行地执行多个HTTP事务。
并行连接可能会T提高页面的加载速度,也可能不一定更快。 打开大量连接会小号很多内存资源,从而引发自身的性能问题。
五、持久连接
web 客户端经常会打开到同一个站点的连接。比如一个web页面内嵌图片来自于一个web站点。
因此。初始化了对某服务器HTTP请求的应用程序很可能会在不久的将来对那台服务器发起更多的请求(如:获取在线图片)。这种性质被称为站点局部性。
在事务处理结束后仍然保持在打开状态的TCP连接被称为持久连接。
持久连接会在不同事务之间保持打开状态,直到客户端或服务区决定将其关闭为止。
说白了 就是为了快 。。对吧。。
1.持久以及并行连接
先说并行连接的缺点,耗时耗宽带;性能降低;可打开的并行连接数量有限。
持久的好处,降低时延,降低建立的开销,减少打开连接的潜在数量。
坏处,可能会累积大量空闲的连接,耗费资源。所有要小心管理。
所以两个配合使用是最高效的方式。打开少量并行,但是每个都是持久。
持久连接有2种类型:HTTP/1.0+keep-alive连接(比较老) 和 HTTP/1.1 persistent连接 (现代)
2.HTTP/1.0+keep-alive连接
去除了进行连接和关闭连接的开销,所以时间会有所缩减。(由于TCP慢启动特性的存在,所以是去除了这个阶段)
3.keep-alive操作
实际HTTP/1.0+keep-alive连接的客户端可以通过包含Connection : keep-alive 首部请求将一条连接保持在打开状态。
如果响应中没有Connection : keep-alive 首部,客户端就认为服务器不支持 keep-alive,会在发回响应报文后关闭连接。
4.keep-alive选项
Connection : keep-alive
keep-alive : max = 5 , timeout = 120
服务器做多还会为另外5个事务保持连接打开状态,打开状态保持到连接空闲了2分钟之后。
参数 max、timeout 是在keep-alive响应首部发送的。估计了服务器还希望多少个事务保持此连接的活跃状态及希望将连接保证在活跃状态的时间。这并不是一个承诺值。
5.keep-alive连接的限制和规则
a.客户端需要发送请求激活keep-alive连接。
b.请求必须随所有希望保持持久连接报文一起发。
c.检测是否响应中是否有请求。没有的话客户端关闭连接。
d.实体的主体部分必须有正确的Content-Length。
e.代理和网关必须执行Connection首部规则
f.不应与无法确定是否支持Connection首部的代理服务器建立keep-alive连接。
g.应忽略所有来自HTTP/1.0 设备的Connection首部字段。
h.在客户端收到完整的响应之前连接就关闭了,客户端需要重试。
6.keep-alive 和哑代理
盲中继:老的 简单的代理都是盲中继,他们只是将字节从一个连接转发到另一个连接中去,不对Connection首部进行特殊的处理。
当客户端与服务器之间存在不解析直接转发的代理时,connection:keep-alive这个首部是直接转发给服务器的,服务器接收了这个请求之后,就会向客户端发送带有connection:keep-alive的响应,
同样盲代理不会解析响应,直接将全部响应转发回客户端。因为客户端收到了这个首部,就认为建立持久连接已经成功了,但是中间的”笨代理“,并不知道这些事情,笨代理只有一种行为模式:在转发请
求和回送服务器响应请求之后就认为这次事务结束了,等待连接断开,而这时由于connection:keep-alive首部已经发送到服务器和客户端,双方都认为持久连接已经建立完成,这样就变成了两边认为持久
连接OK而中间的哑代理等待连接断开的情况,这种情况下如果客户端再一次在这条连接上发送请求,请求就会在亚代理处停止,因为哑代理已经在等待连接关闭。这种状态会导致浏览器一直处于挂起状态,
直到客户端或服务器之中一个连接超时,关闭连接为止,一段美好的牵手就这么没了(哑代理就是把内容原封不动的转发到代理)。为了避免这种情况,现代的代理是不会转发connection:keep-alive这个首部的。
为了防止这个问题,网景提出了一个方案,采用插入Proxy-connection的方式
7.Proxy-connection
这种变通做法引入了一个Proxy-connection 的新首部,解决了盲中继带来的问题,但是没有解决一些其他情况下存在的问题。
第一种情况:是哑代理情况下
客户端 ==>哑代理==>服务器
客户端<==哑代理<==服务器
客户端发送Proxy-connection到哑代理,哑代理还是会把Proxy-connection首部再转发给WEB服务器,服务器不认识Proxy-connection首部,忽略掉了,没有建立keep-alive连接。
第二种情况:聪明代理情况下
客户端 ==>聪明代理==>服务器
客户端<==聪明代理<==服务器
客户端发送Proxy-connection给聪明代理,代理识别出来了Proxy-connection首部,它会发送自己的Connection : keep-alive给服务器 来建立keep-alive连接。
第三种情况:也就是没有解决的问题 哑代理和聪明代理同时存在
客户端 ==>哑代理==>聪明代理==>服务器
客户端<==哑代理<==聪明代理<==服务器
客户端发送Proxy-connection==>哑代理Proxy-connection==>聪明代理Connection : keep-alive==>服务器
客户端Connection : keep-alive<==哑代理Connection : keep-alive<==聪明代理Connection : keep-alive<==服务器
这样又会出现上面讲的那个问题了,仍然是2边建立了持久连接,但是 哑代理仍然在等待关闭连接 然后高高挂起的问题。
8.HTTP/1.1持久连接
用持久连接取代了keep-alive连接,持久连接的工作机制更优一些。持久连接在默认情况下是激活的。要在事务处理结束后连接关闭, HTTP1.1应用程序必须向报文显示添加Connection:close首部。
除非响应包含Connection:close首部,不然HTTP/1.1就会维持在打开状态。当然不发送也不代表服务器会永远保持打开状态,客户端和服务器仍然是可以随时关闭连接的。
9.持久连接的限制和规则
a.客户端发送了Connection:close请求后,无法再发送其他请求了。
b.满足报文长度一致,分块传输编码方式编码--连接才能持久保持。
c.HTTP/1.1代理服务器不应该与HTTP/1.1客户端建立持久连接。因为老的代理会转发Connection首部。
d.HTTP/1.1可以在任意时刻关闭连接。
六、管道化连接
HTTP/1.1允许在持久连接上可选地使用请求管道。
在响应到达前,可以把多条请求放入队列。降低网络环回时间,提高性能。(消除TCP连接时延、消除传输时延)
管道化连接的限制:
-
不是持久连接就不能使用管道。
-
必须按照同样的发送顺序回送响应,因为报文没有标签,很可能就顺序就乱咯。
-
因为可以随时关闭持久连接,所以要随时做好重发准备
-
不应该使用管道化发送重复发送会有副作用的请求(如post,重复提交)。
七、关闭连接的奥秘
1.任意 解除连接
服务器在关闭连接那一刻,不确定客户端是否有数据发送,这样的话,客户端就会在写入半截请求报文时发现出错了。
2.Content-Length及截尾操作
描述响应主体的尺寸,这个是很精确的。当实际长度和Content-Length不匹配时,接收端要质疑长度正确性,缓存代理接收到的话就不缓存这条响应。代理收到就将问题报文转发出去。
3.连接关闭容限、重试以及幂等性
如果一个事务,不管是执行一次还是很多次,结果都是相同的,这个事务就是幂等的。
在执行事务是,传输连接关闭了,除非会带来副作用,否则客户端应该重新打开连接。
副作用就是 发送请求数据时,连接关闭了,客户端无法确认服务器激活了多少事务。比如会重复下订单。
4.正常关闭连接
关闭TCP输入和输出信道的任意一个,或者两个都关闭,如果只关闭一个信道就称之为“半关闭”。简单的HTTP程序可以只使用完全关闭。而有些复杂的对话且使用了持久连接的话,用半关闭来防止对等端遇到错误就十分重要了。
关闭连接的输出信道是很安全的。连接另一端的对等实体会在从其缓冲区读出所有的数据之后会收到一条通知,说明流结束了。这样它就知道你将连接关闭了。
关闭连接的输入信道则比较危险,除非你知道另一端不会再发送信息了。
比如说你在持久连接上发送了10条管道式请求,响应在缓存区存着。当你在发送第11条时,服务器输入信道关闭,这时候 会发生什么?、
首先服务器会发送一个重置信息给你,然后清空你客户端的缓存区。10条没了~~没了~~。在你要去读取数据时呢,得到一个连接被对端重置的错误和缓存响应数据丢失。尽管之前客户端已经接受了这些响应。。
那怎么正常关闭呢?
HTTP规范建议当要突然关闭连接时,应该“正常的关闭连接”,但是它也没说怎么关闭是正确的...
总之,要正常关闭,首先关闭的一端应先关闭自己的输出信道,等待另一端关闭它的输出信道,当两端都告诉对方不会发送任何数据之后,再关闭输入信道,这样连接就完全关闭了,而且也不会出现问题。
但是可控的只能是自己的这端,我们没有办法控制另一端也会这么做,因此如果想要关闭一条连接的话,应该先关闭己端的输出信道,然后周期性的对己端的输入信道进行检查,如果在一段时间之内没有数据传输,那么就可以强制关闭连接,节省资源。
这一章可算写完了,泪目 , 有的地方还是不太理解,先记着。回来再读一遍~~~欧耶\(^o^)/