拿到了盗版的 Web协议与实践(HTTP1.1、网络协议、缓存技术和流量检测)。这本书的正版现在已经买不到了,京东上有这本书,但是也是无货,标价竟然只有33.8元,说实话这个价格连成本都不够。
后来花了90块钱从淘宝买了盗版,书的印刷质量真的不咋样,很多地方都很模糊。不过的确是好书,这是我读过的第一本把HTTP协议讲的很透彻的书(这方面的书本身就不过,之前我看的最多的就是RFC2616)。
PDF版我也拿到了,下载地址:http://www.everbox.com/f/1sGIgc8fWlkblyVGB38pkGc5l9
进入正题。
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输出一定长度的数据)。
<?php set_time_limit(0); // send the contents of the topmost output buffer (if any) and turn this output buffer off ob_end_flush(); // local file that should be send to the client $local_file = 'test.bin'; // filename that the user gets as default $download_file = $local_file; // set the download rate limit (=--> 10 KB/s) $download_rate = 10; if(file_exists($local_file) && is_file($local_file)) { // send headers header('Cache-control: private'); header('Content-Type: application/octet-stream'); header('Content-Length: '.filesize($local_file)); header('Content-Disposition: filename='.$download_file); // flush headers first flush(); // open file stream $file = fopen($local_file, "r"); while (!feof($file)) { // send the current file part to the browser print fread($file, round($download_rate * 1024)); // sleep one second sleep(1); } // close file stream fclose($file); } else { die('Error: The file '.$local_file.' does not exist!'); } ?>
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的应答。
<?php ob_end_flush(); for ($i=0; $i<5; $i++) { echo $i.'
'; sleep(1); } ?>
上述代码在Apache服务器中部署,在浏览器中访问看到的情况会是0到4的数字每隔1S输出一个,但是在“IIS + ISAPI PHP”环境下始终是5个数字一起输出的。
同时我看到了有网友表示在"Nginx + Fast CGI PHP"环境下,PHP的程序缓存控制也会失败,看这里。
呵呵,谢谢
VaTG790i.最好的<a href=http://www.kyfei.com>网站推广软件</a>,
非常好
....................
;ui;普i;uighur;ui;ui;个
在unix网络编程中看到了关于TCP/IP的一些内容,我感觉还是写的不够。正在下载中,一定
下载地址呢