HTTP/1.1之连接(第八章)
8.1 持久性连接
目的:
在以前,没有持久性连接的时候,为了获取每一个URL都要进行一次TCP连接,这显然加重了服务器的负担,容易引起互联网的堵塞,因为你要多次进行三次握手,尤其是页面里面有很多内联的图片、css样式表、js文件时候,简直让人崩溃。所以,持久连接有以下特点:
- 通过建立较少的TCP连接,可以节省不少路由与主机(包含服务器端和用户端)cpu利用率,而且还能节省用于tcp协议控制块的内存。
- 显然,一个连接,多次传输节省了时间开销。
- 网路阻塞会减少,因为少发了很多握手连接的数据包。
- 改进越来越优雅,错误报告,不用关闭连接,而老的必须关闭连接,然后重试新连接。
8.1.2 总体操作
在HTTP/1.1中,持久连接应该是必须的,默认的。不需要协商都应该采用的方式。也就是,默认,客户端和服务端都是持久连接,即使服务器的错误响应,也当如此。
连接总要终止的,在数据发送完成以后,应该关闭。可以利用Connection的头域,发送close信息来关闭连接。
8.1.2.1 协商
主要是协商怎样断开,任何一方(用户浏览器or服务器)都可以随时选择断开连接,唯一要做的就是,在Connection头域发送一个close信息,这个信息将会是他们连接的最后一条信息。
8.1.2.2 管线
管线就是说,可以以管线的方式,发送数据,无须等待响应,而发送多条请求,服务器端必须根据信息的先后顺序来发送响应。
在第一次管线连接失败的时候,客户端应该去尝试重新连接,这个时候,只有确认了当前的连接是持久性连接的时候,才能发起管线连接。同时,如果服务器在发出所有的响应之前关闭了连接,这个时候,客户端还需要重新发送请求。
8.1.3 代理
代理非常重要,在4章中,我们知道,一个代理不应该改变头域的值,代理必须同时向客户端和源服务器指明持久性连接,而且,在后文中,我们可以发现,代理保持持久连接的时间要更长,因为,同一个页面,可能会有多个人来访问。
8.1.4 实际考虑
持久连接必须要有一个超时的时限,要不然,没有请求发送,双发的close信息丢失,会导致资源无法释放。代理的时间要更长的原因是,用户对同一个源服务器可能发送多个请求。
客户端和服务器端必须能够要优雅的协商,有没有这么一种情况 :
客户端正想去发送请求的时候,服务器端,发出一个终止连接的响应(资源被闲置)。这说明,服务器和客户端必须有一个机制,能够从连接的异步事件中恢复。只要请求是等幂的,客户端软件(浏览器)应该不需要用户交互的情况下,重新发送请求。如果再次请求的序列仍然失败了,那就不再重试了。
8.2 信息传送的要求
8.2.1 持久连接与流量控制
持久连接的流量控制是使用TCP的流量控制来进行的。
8.2.2 监视连接中的错误信息
如果客户端与服务器端通信的过程中发生了错误,应当立即停止传送,如果是以块传送编码方式传送,则可以发送长度为0的块和空尾部来提前标记传输结束。如果先前已经发送了Content-length的话,就必须关闭连接了。
8.2.3 100码的用途
有时候,服务器闹点小情绪,人家不想看你的信息主体,这个时候再去发送信息主体,就有点让人烦躁了。所有用一个100码来探测,是否愿意继续接受主体信息。
HTTP/1.1 的客户端的要求:
如果不打算发送信息主体,就不要发送100-continue的Expect的头域,如果你想要在发送信息主体前接受到100的响应,就必须发送上述头域。由于旧实现的原因,你发送了这样的头域以后,不能无止尽的等待服务器端响应100呐,得迷途知返呐。
HTTP/1.1 的服务器端的要求:
一个服务器接收到一个100-continue的头域以后,要么就回应100请求继续发送,要么就发送最终的状态响应码,你不能在发送100之前接受信息,当然,如果你发送了最终响应码以后,就不应该再接受信息主体。要么就,接收到了以后,直接丢弃了,切不能执行GET等方法。
如果对方没有发送100-continue的头域,服务器就不哟啊发送100了。如果请求来自于HTTP/1.0,也不应该发送,否则那边是无法识别的。
一旦消息被接受,并被处理,发送100的源服务器应该要发送一个结束的响应信息,除非源服务器过早的断开了传输层的连接。
代理的行为规则:
如果代理接收到一个100-continue的头域,在不知道源服务器(或代理服务器)的http协议版本的时候,需要直接转发这个头域,如果已经知道对方是http/1.0,那么就应该去这个头域,并且返给客户端一个417(期望失败)的响应。这个版本号应该维护一个缓存。如果一个客户端的版本是HTTP/1.0,那么代理就不应该转发100的返回码。
服务器过早关闭的时候,客户端的请求算法:
如果一个客户端发送了一个带有100-continue的Expect的头域,并且,这个客户端没有直接与源服务器连接,并且他在接受到状态码前已经发现了断开了连接,这个时候,他需要重试连接。会遵循以下的过程。
- 初始化一个新的连接。
- 发送请求头域
- 初始化一个变量值R,这个值代表了到服务器的一个回路的时间(当然是估计的),或者是直接初始化为5S。
- T = R*(2**N) N代表重试的次数。
- 等待T秒,或者是服务器端的错误信息。
- 如果收到错误信息,T秒后,重传请求主体。
- 如果客户端提前发现连接关闭,则重复1进行重试,知道下面三种情况,一,成功的把请求发送出去了,二,收到错误信息而终止,三,用户受不了了,主动终止了重试。
在任意点上,客户端如果接收到错误信息,应该立即终止连接。
所谓幂等指对同一URL的多个请求应该返回同样的结果。比如sina网中点击某一个新闻页面,不同的时候返回应该是同一篇文章,如果后台有修改这条新闻,用户所看到的内容不同,但是我们还是会认为这是幂等的。