• HTTP/1.1组块(chunked)传输编码实验


    HTTP/1.1组块(chunked)传输编码实验_redice's Blog

    HTTP/1.1组块(chunked)传输编码实验

    拿到了盗版的 Web协议与实践(HTTP1.1、网络协议、缓存技术和流量检测)。这本书的正版现在已经买不到了,京东上有这本书,但是也是无货,标价竟然只有33.8元,说实话这个价格连成本都不够。

     
    后来花了90块钱从淘宝买了盗版,书的印刷质量真的不咋样,很多地方都很模糊。不过的确是好书,这是我读过的第一本把HTTP协议讲的很透彻的书(这方面的书本身就不过,之前我看的最多的就是RFC2616)。
    PDF版我也拿到了,想要的发邮件吧。
     
    进入正题。
     
    HTTP是如何确保参与各方(通常是浏览器和Web服务器)认识到它们已经接收到了完整的消息?
     
           实体的长度是一个重要的指示符,接收方据此可知道何时收到了完整的实体。HTTP/1.0可用来指定实体长度的唯一机制是通过Content-Length字段。静态资源的长度可以很容易地确定;但是对于动态生成的响应来说(比如在 phpMyAdmin中导出数据库的操作,数据的大小是事先不能确定的),为获取它的真实长度,只能等它完全生成之后,才能正确地填写Content-Length的值,这便要求缓存整个响应,从而增大了最终用户的延迟。在HTTP/1.0中,服务器可以通过关闭连接来指示动态内容的结尾,如果关闭连接是指示动态响应结尾的唯一办法,那么HTTP/1.1的持久连接便不可能实现了(TCP链接复用、持久化连接是HTTP/1.1的一个重大改进,它可以提高带宽的利用率)。
          为了解决这个问题,HTTP/1.1引入了被称为组块(chunked)的传输编码方法。该方法使发送方能将消息实体分割为任意大小的组块(chunk),并单独地发送他们。在每个组块前面,都加上了该组块的长度,使接收方可确保自己能够完整地接收到这个组块。更重要的是,在最末尾的地方,发送方生成了长度为零的组块。接收方可据此判断整条消息都已安全地传输完毕。这样也避免了在服务器端占用大量的缓存。Transfer-Encoding标头(值为chunked)向接收方指出:响应将被分组块,对响应分析时,应采取不同于非分组块的影响方式。
     
    上面是我对,Web协议与实践7.6节“消息传输”的概括。
     
    下面是两个实验:
    测试环境: Apache + PHP。
    测试脚本如下:
    这段代码的功能是限速下载,它是从http://www.jonasjohn.de/snippets/php/dl-speed-limit.htm获取的。
    它读取服务器的一个文件,然后动态地输出该文件的数据(每隔1S输出一定长度的数据)。
    1. <?php  
    2. set_time_limit(0);  
    3.   
    4. // send the contents of the topmost output buffer (if any) and turn this output buffer off  
    5. ob_end_flush();  
    6.   
    7.   
    8. // local file that should be send to the client  
    9. $local_file = 'test.bin';  
    10.    
    11. // filename that the user gets as default  
    12. $download_file = $local_file;  
    13.    
    14. // set the download rate limit (=--> 10 KB/s)  
    15. $download_rate = 10;  
    16.    
    17. if(file_exists($local_file) && is_file($local_file)) {  
    18.    
    19.     // send headers  
    20.     header('Cache-control: private');  
    21.     header('Content-Type: application/octet-stream');  
    22.     header('Content-Length: '.filesize($local_file));  
    23.     header('Content-Disposition: filename='.$download_file);  
    24.   
    25.    // flush headers first  
    26.    flush();  
    27.    
    28.     // open file stream  
    29.     $file = fopen($local_file"r");  
    30.    
    31.     while (!feof($file)) {  
    32.    
    33.         // send the current file part to the browser  
    34.         print fread($fileround($download_rate * 1024));  
    35.    
    36.         // sleep one second  
    37.         sleep(1);  
    38.     }  
    39.    
    40.     // close file stream  
    41.     fclose($file);  
    42.    
    43. }  
    44. else {  
    45.     die('Error: The file '.$local_file.' does not exist!');  
    46. }  
    47. ?>   
    ob_end_flush()将确保脚本执行过程中不使用缓存,这意味着任何输出的数据都将立即被发送到客户端。
     
    1)带Content-Length的响应。
    如上述代码,在应答头中我们手动添加了Content-Length字段(该值由文件的实际大小决定)。
    在浏览器(Firefox)中访问该脚本,立即弹出下载对话框,应答头如下图所示。
     
     
    我们可以看到应答头中包含了Content-Length标头字段。
    下载进度如下图所示,FireFox下载管理器之所以能够准确地显示出下载进度就是因为Content-Length字段已经指示了文件的总大小。
     
     
       
     2)不带Content-Length的响应。
    将上述代码中的header('Content-Length: '.filesize($local_file));语句注释掉。
    在浏览器(Firefox)中访问该脚本,立即弹出下载对话框,应答头如下图所示。
     
     
     在应答头中我们可以看到Transfer-Encoding: chunked,说明这次服务器使用了组块式的应答。
    看一下载管理器,如下图所示。由于此时不确定文件的总大小,因此它不能准确得显示出下载进度。
     
     
     
     特别说明:经过测试发现“IIS + ISAPI PHP”不支持关闭程序执行过程中的缓存(flush(), ob_implicit_flush(true), ob_end_flush()均不起作用)。注意本文所说的缓存都指的是PHP解释器在执行PHP代码过程中使用的内存缓存区(变量),而不是服务器或客户端的文件缓存。
    所以如果在“IIS + ISAPI PHP”环境下做实验二,服务器总是会将数据先放到缓存中直到程序执行完毕,得到Content-Length值后,发送非chunked的应答。
     
    1. <?php  
    2. ob_end_flush();  
    3.   
    4. for ($i=0; $i<5; $i++) {  
    5.    echo $i.'<br>';  
    6.    sleep(1);  
    7. }  
    8. ?>   

    上述代码在Apache服务器中部署,在浏览器中访问看到的情况会是0到4的数字每隔1S输出一个,但是在“IIS + ISAPI PHP”环境下始终是5个数字一起输出的。

    同时我看到了有网友表示在"Nginx + Fast CGI PHP"环境下,PHP的程序缓存控制也会失败,看这里

  • 相关阅读:
    java 原子性 可见性 有序性
    java中Array/List/Map/Object与Json互相转换详解(转载)
    观察者模式(转载)
    TCP协议
    “数字签名”与“数字证书”
    两道笔试题
    定时任务处理过程中的问题
    行数据库VS列数据库
    B树和B+树
    ThreadPoolTaskExecutor介绍
  • 原文地址:https://www.cnblogs.com/lexus/p/2416609.html
Copyright © 2020-2023  润新知