苹果推送服务器推送延迟_HTTP / 2服务器推送

苹果推送服务器推送延迟

HTTP协议的新版本HTTP / 2允许服务器在客户端请求特定内容之前将内容推送到客户端。 如果将旧版本1.1与新版本2进行比较,协议中还有许多其他修改,但是在本文中,我将重点介绍推送功能。 我将简要讨论如何在servlet中使用它,并且还将讨论一些有关如何测试并了解它是否真正起作用的知识。 在撰写本文之前,我的初衷是创建一个HTTP / 2演示,该示例显示使用推入示例页面加载与不使用推入示例页面加载相比有多快。 这将是PACKT发布的视频教程中的一章。 在示例应用程序的开发过程中,我遇到了一些问题,我阅读了一些教程并调试了示例代码,从而积累了一些经验。 在本文中,我与您分享了这种经验。 这样,本文不仅仅是一个简单的入门教程。 但是,TLDR也更长一些。 如果您不耐烦。

HTTP版本

HTTP / 2是HTTP协议的新版本。 该协议在2之前具有三个版本。它们分别是0.9、1.0和1.1。 第一个只是从1991年开始的实验。第一个实际版本是1996年发布的1.0。如果您当时使用互联网并且仍然记得Mosaic浏览器,则可能是该版本。 此版本很快之后是1997年的1.1版。1.0和1.1之间的主要区别在于Host标头字段使在一台计算机,一台服务器,一个IP地址和一个端口上运行多个网站成为可能。

Http

HTTP 1.1

1.0和1.1版本都非常简单。 客户端打开一个通往服务器的TCP通道,并将请求以纯文本形式写入其中。 该请求以请求行开始,然后是标题行,空行和请求的正文。 主体可以是二进制的。 响应具有相同的结构,除了第一行不是特定于请求的行,而是明显的响应。

恕我直言,简单的方法近来非常重要,因为它不可避免地有助于协议的传播和使用。 您可以在不同领域的行业中找到这种类型的模式。 这就是世界以敏捷方式发展的方式。 首先,您开发出一些简单的可行的工具,然后继续使它变得越来越复杂,因为环境要求它对更复杂的功能有更强的渴望。 第一次大胆尝试并寻求复杂而完美的解决方案通常是行不通的。 如果您还记得电影《星球大战》(Star Wars),您会知道死亡之星永远不会完结,最后会被夷为平地。 但这并不意味着我们开始的简单版本没有问题。

HTTP / 1.1问题

HTTP / 1.1有很多问题。 一个真正的英国人可能会说使用网络并不是最佳选择。 浪费带宽。 HTTP发明网页的早期是文本。 今天,它是文本,CSS,JavaScript,图像,声音,视频以及数字化的气味,味道和触摸样本,更不用说直接的神经刺激命令文件了。 在此税收列表中,紧随视频之后的这些最后内容类型仍然很少见,但您应该做好准备,这就是HTTP / 2的目标。 为未来做准备。 使用HTTP / 1.1,浏览器会在单独的TCP通道中依次下载这些资源。 服务器或客户端可以处理的TCP通道数量是有限的,因此浏览器限制自己打开的TCP通道不能超过四个。 这意味着在下载页面的四个内容元素时,其他元素在队列中等待下载。 如果我们的下载内容很慢,则可能会阻止整个网页的下载。 您可以通过编写一些简单的servlet来运行实验,该servlet将复杂HTML页面发送到浏览器,然后让某些内容元素缓慢下载,而让其他内容元素快速下载。 使用Chrome在调试模式下进行操作,您将获得漂亮的甘特图,显示下载时间。

该网络还浪费了为每个新的HTTP连接创建新的TCP通道。 创建TCP通道需要从客户端到服务器的SYN数据包,然后是从服务器到客户端的SYN-ACK,然后又是从客户端到服务器的ACK,然后才能开始发送数据。 除此之外,TCP协议还限制了自身不会向丢失通道注入大量数据,这些数据无论如何都会丢失,因此它启动缓慢,仅在开始时发送少量数据包,并且仅在启动时才提高速度看到包裹的形状和内容良好。 让我们考虑一下启动TCP通道的三向握手。 客户端和服务器之间的网络具有一定的滞后性和带宽。 滞后是程序包从客户端到服务器或以其他方式传播所需的时间。 带宽是在给定时间内(例如一秒钟)可以通过客户端和服务器之间的网络推送的位数。 想象一下您用来填充水桶的软管。 如果很长,打开水龙头后可能要花两三秒钟才能开始倒水。 如果狭窄,则需要一分钟才能装满水桶。 在这种情况下,开始时2-3秒并不重要,无论如何您都必须等待一分钟。 另一方面,如果软管较宽,则水可能会在十秒钟内充满桶中的水。 三秒钟的延迟是30%。 这很重要。 同样,在带宽充足的快速网络中,TCP通道的缓慢启动延迟也很明显。 幸运的是,我们朝着这个方向前进。 我们在家中获得了光纤,取代了19.2kbps的拨号调制解调器。 但是,与此同时,HTTP / 1.1延迟是一个日益严重的问题。

有一个标头字段Keep-alive ,可以告诉服务器不要关闭TCP通道,而是将其重用于下一个HTTP请求,而HTTP / 1.1上的此修补程序虽然有很多帮助,但还不够。 阻塞缓慢的资源问题仍然存在。 HTT / 1.1还存在HTTP / 2所解决的其他问题,但是,使用许多TCP通道从同一服务器将多个内容片段下载到客户端是与服务器推送相关的主要问题,这确实是本文的主题。

HTTP / 2

HTTP / 2在服务器和客户端之间使用单个TCP通道。 当从不同的服务器下载内容时,客户端最终将为每个服务器打开单独的TCP通道,但是对于来自同一服务器的内容,HTTP / 2仅使用一个TCP通道。 在特定客户端和单个服务器之间使用多个TCP通道不会加快通信速度,这只是HTTP / 1.1中的一种解决方法,可以部分缓解资源缓慢的阻塞效应。

一个请求和一个相应的响应不专门使用HTTP / 2中的TCP通道。 有框架,请求和响应在这些框架中传播。 如果内容块创建缓慢且一段时间未使用通道,则其他资源可以获取帧并可以在同一TCP通道中传输。 在许多情况下,这极大地提高了下载速度。 对于浏览器程序是JavaScript还是WebAssembly,此更改也是透明的。 对于WebAssembly,更改非常简单:WebAssembly不直接处理XMLHttpRequest,而是使用JavaScript实现和导入的函数。 对于JavaScript,浏览器隐藏了传输的复杂性。 JavaScript网络API与以前相同。 您请求一个资源,您得到一个,并且您不必关心该资源是在其专用的TCP通道中传输,混入HTTP / 2帧还是由鸽子邮递发送给您的。 在服务器端,方法是相同的。 如果是Java,则Servlet应用程序获取请求并创建响应。 容器,Web服务器和客户端浏览器如何使其通过网络传输取决于它。

服务器应用程序可能发生变化的唯一区别是服务器推送。 这是一项新功能,新的API为服务器应用程序向客户端启动内容推送提供了额外的可能性。

什么时候推,什么推?

服务器推送通常可在以下情况下使用:应用程序缓慢准备一些内容,并且应用程序知道这将很慢,并且还知道还有其他资源,通常是许多小图标图像,可以快速下载并客户需要。 因此,服务器推送的条件为(PRECONDITIONS)

  • 请求的内容很慢,
  • 应用程序知道它会变慢,
  • 下载此资源后,客户端还有其他资源,
  • 应用程序知道这些资源是什么,
  • 这些资源可以快速下载。


在这种情况下,小服务程序可以启动一个或多个推送,以便在准备主要内容时将内容传递到浏览器。

当主要内容准备就绪时,客户端浏览器就会意识到它需要它们已经存在的额外资源。

如果我们不推送资源,则只有在浏览器意识到需要额外的资源时,才在处理原始资源后才下载资源。

在一个简单的示例中,当浏览器看到所有img标签并知道它需要图标图像才能呈现页面时。

这就是上面的动画试图以简单的方式显示的内容。

如何推

要发起推送,不仅简单。 每当Servlet在请求对象req上调用req.newPushBuilder()时,Servlet标准4.0都会扩展HttpServletRequest以创建一个新的PushBuilder 。 推构建器可用于创建推,然后在其上调用方法push()将启动向客户端的发送。 它是如此简单。 您必须设置的唯一参数是要推送的资源的路径。

var builder = req.newPushBuilder();
...
builder.path(s).push();

样品申请

测试服务器推送的示例应用程序是一个servlet,该servlet响应一个HTML页面,该页面在10×10的表中包含一百个图像引用。 从本质上讲,这些是http://www.flaticon.com网站上的小图标

servlet要做的第一件事是通过服务器推送来启动图标下载。 为此,它将创建一个推入构建器,并且使用该单个对象来发起100次推入。 之后,Servlet进入睡眠状态。 这种睡眠模拟了Servlet响应的内部缓慢运行。 此时的实际应用程序将从其他数据库,其他服务等收集发送响应所需的信息。 在此期间,服务器和客户端有足够的时间下载PNG文件。 响应到达时,文件就在那里,图像即刻显示。 至少这是我们所期望的。

Servlet有一个名为push的参数,可以为10 。 如果此参数为1则Servlet将PNG文件推送到客户端,为0则为0 。 这样,我们可以轻松比较两种不同行为的速度。

public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        final String titleText;
        var builder = req.newPushBuilder();
        var etag = now();
        if (builder == null) {
            titleText = "Good old HTTP/1.1 download";
        } else {
            var pushRequested = parse(req).get("push", 1) == 1;
            if (pushRequested) {
                titleText = "HTTP/2 Push";
                sendPush(req, builder, etag);
            } else {
                titleText = "HTTP/2 without push";
            }
        }
        var lag = parse(req).get("lag", 5000);
        var delay = parse(req).get("delay", 0);
        var sleep = new ThrottleTool.Sleeper();
        sleep.till(lag);
        resp.setContentType("text/html");
        sendHtml(req, resp, titleText, etag, delay, sleep);
    }

Servlet还可以使用查询参数lagdelay进行参数设置。

lag是指从servlet的开始算起,servlet开始向客户端发送HTML页面之前所Hibernate的毫秒数。 默认值为5000,这意味着HTML发送将在servlet启动后5秒开始。

delay是servlet在每个图像标签之间Hibernate的毫秒数。 缺省值为零,这意味着servlet以最快的速度发送HTML。

对于推送,有趣的是我们如何获得构建器对象。 线

var builder = req.newPushBuilder();

返回一个新的生成器对象,该对象也可以为null。 如果环境不允许推送,则为null。 最简单的情况是通过普通HTTP而非HTTPS查询servlet。 HTTP / 2仅在TLS安全通道上工作,这样,如果我们通过HTTP打开Servlet,它将无法进行任何操作。

此后,方法sendPush()会按名称所示发送推送内容。 方法如下:

private void sendPush(HttpServletRequest req, PushBuilder builder, long etag) {
        for (var i = 0; i < 10; i++) {
            for (var j = 0; j < 10; j++) {
                var s = imagePath(i, j, req, etag);
                builder.path(s);
                builder.push();
            }
        }
    }

方法imagePath()根据索引计算png的相对URL,并通过推送构建器指定此路径。 最终要求构建者推送内容。 对此push()调用push()启动服务器上的推送。

在此示例中,构建器实际使用了一百次。 每次推送我们都不需要新的构建器对象。 我们可以安全地重用相同的对象。 唯一的要求是,我们需要在下一次推送之前设置所有参数。 这通常只是路径。

影像服务器

在演示应用程序中,服务器不直接提供图标图像。 图标资源的URL映射到一个servlet,该servlet从磁盘读取图标PNG并将其写入响应。 原因是双重的。 按时间顺序排列的第一个原因是,在应用程序调试期间,我需要有关何时以及如何收集资源的信息,并且在资源只是服务器直接处理的纯文件的情况下,我没有太多可能调试或记录任何内容。 第二个原因是该演示需要网络限制。 就像主HTML资源在呕吐HTML文本之前等待5秒钟一样,也需要放慢速度以显示出良好的演示效果。 浏览器的调试模式中具有节流功能。 但是,Chrome上的这种限制似乎在架构上介于临时存储推送资源的缓存和DOM显示引擎之间。 从实验的角度来看,在我们的代码中的演示服务器上实现限制当然是一个不错的选择,并且已经推送和下载的资源正在被限制加载到屏幕中是不可能的。

因此,图像servlet具有两个查询参数。 imglag是命中到达后开始执行任何操作之前servlet等待的毫秒数。 如果缺少该参数,则默认值为300毫秒。 另一个参数是imgdelay ,它指定服务器将图像字节发送到客户端所imgdelay的毫秒数。 这是通过以下方式实现的:服务器逐个发送每个字节,并且如果当前时间成比例地太快而无法为下一个字节提供服务,则服务器会睡一会儿。 默认值为1000,这意味着每个图标在大约1.3秒内从服务器交付。 从服务器推送的角度来看,代码本身并不太具有教育意义。 您可以在GitHub存储库中看到它https://github.com/verhas/pushbuilder/blob/master/src/main/java/javax0/pushbuilder/demo/ImageServer.java

PushBuilder方法

如果您需要构建具有某些特殊特征的请求,则PushBuilder类还有许多其他方法。 当您发起对资源的推送时,您实际上定义了一个HTTP请求,该资源就是答案。 实际资源由服务器提供。 如果它是普通的静态资源(例如图像),则服务器将从文件系统中将其拾取。 如果它是一些动态计算的资源,则服务器将启动请求所针对的servlet。 推构建器真正建立的是一个保留并在服务器上使用的请求,而客户端在资源被推后实际上将永远不会发出此请求。 类设置请求属性的设置方法,例如参数,标头等。

method()

您可以设置资源作为响应的请求的方法。 默认情况下,这是GET ,大多数情况下应该可以。 如果资源是对
POSTPUTDELETECONNECTOPTIONSTRACE请求,那么我们无论如何都不能推送资源,因为HTTP / 2标准不允许推送此类资源。 剩下的就是似乎没有意义的HEAD方法。 我相信方法method()在接口中

  • 出于兼容性原因,如果有新方法,
  • 为了某些使用专有非标准方法的应用程序
  • 或开个玩笑(一种称为method的方法)。

sessionId()

此方法可用于设置通常在JSESSIONID cookie或请求参数中携带的会话ID。

您可以使用这些方法修改请求的标头。 调用setHeader() ,应该替换先前的值。 addHeader()添加一个新的头。 当您重复使用同一对象时,一次又一次添加相同的标头可能会在请求中多次导致相同的标头。 最后, removeHeader()删除标题。

请注意,某些教程还添加了标题Content-type ,而在某些教程中,该值是image/png 。 即使它没有任何危害,这也是错误的。 我们在推送构建器上设置的标头用于请求资源。 在我们的示例中,图像不是由Tomcat直接访问的,而是通过servlet传递的。 该servlet从磁盘读取PNG文件的内容,并将其发送到从响应对象获取的writer。 该Servlet将看到在推送构建器中设置的标头。 如果将内容类型设置为image/png ,则可能认为我们确实是一种特殊的愚蠢行为,它发送的是PNG格式的HTTP GET请求主体。 通常,这并不重要,servlet和服务器倾向于忽略GET请求的内容类型,尤其是当内容的字节数为零时。 不存在的图片有什么格式?

您可以在推送构建器对象上设置的内容也可以退出。 您可以使用这些getHeader()getMethod()getHeaderNames()getPath()等方法来查看推构建器中值的当前值。

实验

在实验过程中,无论有无推送,我都看不到HTTP / 2之间的任何区别。 使用HTTP / 2的下载速度必然比HTTP / 1.1快,但是推送和非推送版本之间没有区别。 我使用的是Chrome版本67.0.3396.99(正式版)(64位)。 浏览器支持推功能,但是开发人员工具不支持推的调试。 推送的内容显示为正常下载的内容。 有一些秘密的内部URL(嗯,因为它是在网络上发布的,所以并不是真正的秘密),它可以显示实际的框架,但是不太方便。 我终于在那儿看到的是,推送本身起作用了。 当服务ServletHTML HTML主页面处于Hibernate状态时,图像被推送到浏览器,但是在那之后,即使我打开了浏览器缓存,浏览器仍在重新下载图像。

由于HTTP / 2是由SPDY协议启动的,并且由Google推送(再次缩进),所以我坚信这是我的代码做错了什么。 最后,我放弃并启动了Firefox,然后开始运行,这是您在屏幕截图中可以看到的内容:



总结外卖

服务器推送是一个有趣的话题,也是一项强大的技术。 要使用它,有很多先决条件(请参见上面列出的内容,搜索“ PRECONDITIONS”)。 如果所有这些都满足,那么您可以考虑实施它,但是您应该使用不同的网络设置,延迟和不同的客户端实现进行实验。 如果客户端实现不尽人意,那么一键下载的下载速度可能会比不带一键下载的下载速度慢。 客户中有很大的发展空间。 其中的一些发展将使浏览器处理服务器推送资源的方式更加成熟,但是我几乎可以肯定,我们还将很快拥有JavaScript API,该API可以注册在推送开始时触发的回调函数,从而不仅可以可以拒绝推送流但可以拒绝客户端JavaScript的自主浏览器。 对于HTTP / 2的开发,请睁大双眼。

参考资料

翻译自: https://www.javacodegeeks.com/2018/07/http-2-server-push.html

苹果推送服务器推送延迟

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值