HTTP keep

您所在的位置:网站首页 keepingalive HTTP keep

HTTP keep

2024-07-08 14:31:12| 来源: 网络整理| 查看: 265

1.为什么要有Connection: keep-alive?

在早期的HTTP/1.0中,每次http请求都要创建一个连接,而创建连接的过程需要消耗资源和时间,为了减少资源消耗,缩短响应时间,就需要重用连接。在后来的HTTP/1.0中以及HTTP/1.1中,引入了重用连接的机制,就是在http请求头中加入Connection: keep-alive来告诉对方这个请求响应完成后不要关闭,下一次咱们还用这个请求继续交流。协议规定HTTP/1.0如果想要保持长连接,需要在请求头中加上Connection: keep-alive,而HTTP/1.1默认是支持长连接的,有没有这个请求头都行。

当然了,协议是这样规定的,至于支不支持还得看服务器(比如tomcat)和客户端(比如浏览器)的具体实现。在实践过程中发现谷歌浏览器使用HTTP/1.1协议时请求头中总会带上Connection: keep-alive,另外通过httpclient使用HTTP/1.0协议去请求tomcat时,即使带上Connection: keep-alive请求头也保持不了长连接。如果HTTP/1.1版本的http请求报文不希望使用长连接,则要在请求头中加上Connection: close,接收到这个请求头的对端服务就会主动关闭连接。

但是http长连接会一直保持吗?肯定是不会的。一般服务端都会设置keep-alive超时时间。超过指定的时间间隔,服务端就会主动关闭连接。同时服务端还会设置一个参数叫最大请求数,比如当最大请求数是300时,只要请求次数超过300次,即使还没到超时时间,服务端也会主动关闭连接。

2.Transfer-Encoding和Content-Length

谈到http长连接,都绕不开这两个请求/响应头。其中Transfer-Encoding不建议在请求头中使用,因为无法知道服务端能否解析这个请求头,而应该在响应头中使用,因为客户端浏览器都能解析这个响应头。Content-Length在请求方法为GET的时候不能使用,在请求方法为POST的时候需要使用,同时也常常出现在响应头中。为了方便描述,下面只说明响应头中出现这两个属性的情况。

要实现长连接很简单,只要客户端和服务端都保持这个http长连接即可。但问题的关键在于保持长连接后,浏览器如何知道服务器已经响应完成?在使用短连接的时候,服务器完成响应后即关闭http连接,这样浏览器就能知道已接收到全部的响应,同时也关闭连接(TCP连接是双向的)。在使用长连接的时候,响应完成后服务器是不能关闭连接的,那么它就要在响应头中加上特殊标志告诉浏览器已响应完成。

一般情况下这个特殊标志就是Content-Length,来指明响应体的数据大小,比如Content-Length: 120表示响应体内容有120个字节,这样浏览器接收到120个字节的响应体后就知道了已经响应完成。

由于Content-Length字段必须真实反映响应体长度,但实际应用中,有些时候响应体长度并没那么好获得,例如响应体来自于网络文件,或者由动态语言生成。这时候要想准确获取长度,只能先开一个足够大的内存空间,等内容全部生成好再计算。但这样做一方面需要更大的内存开销,另一方面也会让客户端等更久。这时候Transfer-Encoding: chunked响应头就派上用场了,该响应头表示响应体内容用的是分块传输,此时服务器可以将数据一块一块地分块响应给浏览器而不必一次性全部响应,待浏览器接收到全部分块后就表示响应结束。

以分块传输一段文本内容:“人的一生总是在追求自由的一生 So easy”来说明分块传输的过程,如下图所示 分块传输示意图 图中每个分块的第一行是分块内容的大小,十六进制表示,后面跟CRLF(\r\n),第一行本身以及分块内容末尾的CRLF不计入大小。第二行是分块内容,后面也跟CRLF。最后一个分块虽然大小为零,但是必不可少,表示分块的结束,后面也跟CRLF,同时内容为空。最后,响应体以CRLF结束。将它们结合起来的响应内容就是:

HTTP/1.1 200 OK Content-Type: text/plain;charset=utf-8 Connection: keep-alive Transfer-Encoding: chunked 21\r\n 人的一生总是在追求自由\r\n 11\r\n 的一生 So easy\r\n 0\r\n \r\n

不过以上格式的响应体内容用浏览器自带的调试工具是看不出来的,浏览器自带调试工具对分块传输和非分块传输响应体的显示是一样的,要想看到区别,需要用Wireshark、Fiddler等抓包工具查看。

3.HTTP keep-alive和TCP keepalive的区别

TCP keepalive指的是TCP保活计时器(keepalive timer)。设想有这样的情况:客户已主动与服务器建立了TCP连接。但后来客户端的主机突然出故障。显然,服务器以后就不能再收到客户发来的数据。因此,应当有措施使服务器不要再白白等待下去。这就是使用保活计时器。服务器每收到一次客户的数据,就重新设置保活计时器,时间的设置通常是两小时。若两小时没有收到客户的数据,服务器就发送一个探测报文段,以后则每隔75秒发送一次。若一连发送10个探测报文段后仍无客户的响应,服务器就认为客户端出了故障,接着就关闭这个连接。

​ ——摘自谢希仁《计算机网络》

针对linux系统,TCP保活超时时间、探测报文段发送间隔、探测报文段最大发送次数都是可以设置的,如下

# cat /proc/sys/net/ipv4/tcp_keepalive_time 7200 当keepalive启用的时候,TCP发送keepalive消息的频度。缺省是2小时 # cat /proc/sys/net/ipv4/tcp_keepalive_intvl 75 当探测没有确认时,重新发送探测的频度。缺省是75秒 # cat /proc/sys/net/ipv4/tcp_keepalive_probes 9 探测尝试的次数。如果第1次探测包就收到响应了,则后8次的不再发 4.分块传输示例代码

这是用netty4写的示例代码,主要用到了netty中关于HTTP协议的编解码部分,目的是用来自定义分块传输的块大小。运行程序后,可以在ctx.writeAndFlush(httpContent);处打个断点,一个分块一个分块地调试,同时用wireshark抓TCP包,可以发现每响应一个分块,都会产生一次TCP传输,同时浏览器页面也会实时显示最新的响应数据(运行环境:Ubuntu 16.04LTS + Firefox63.0 + netty4.1.15.Final,强调运行环境是因为在mac系统的火狐或者谷歌浏览器中,无法重现同时浏览器页面也会实时显示最新的响应数据这个现象)。

package cn.cjc.keepalive; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.*; import io.netty.util.CharsetUtil; /** * @author chenjc * @since 2017-10-14 */ public class KeepAliveTest { public static void main(String[] args) { NioEventLoopGroup group = new NioEventLoopGroup(); try { ServerBootstrap sb = new ServerBootstrap(); sb.group(group) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline() .addLast(new HttpServerCodec()) .addLast(new HttpObjectAggregator(512 * 1024)) .addLast(new HttpRequestHandler()); } }); ChannelFuture future = sb.bind(8088).sync(); System.out.println("==========服务已启动=========="); future.channel().closeFuture().sync(); System.out.println("==========服务已关闭=========="); } catch (InterruptedException e) { e.printStackTrace(); } finally { group.shutdownGracefully(); } } private static class HttpRequestHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception { DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); HttpHeaders headers = response.headers(); boolean keepAlive = HttpUtil.isKeepAlive(fullHttpRequest); if (keepAlive) { headers.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN + ";charset=utf-8"); headers.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); headers.add(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED); // headers.add(HttpHeaderNames.CONTENT_LENGTH, 11 * 10 + 1);//+1的原因是最后一个分块的10占两个字节 } ctx.writeAndFlush(response);//写响应行和响应头 for (int i = 1; i cause.printStackTrace(); ctx.close(); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println("inactive"); } @Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { System.out.println("unregister"); } } } 参考资料 http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/http://www.cnblogs.com/cswuyg/p/3653263.htmlhttp://xls9577087.iteye.com/blog/2268698


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭