• fsockopen与chunked分段传输

    如何处理这种情况?
    服务器君一共花费 7.981 ms 进行了 4 次数据库查询,努力地为您提供了这个页面。
    广告很萌的

    还是根据上一节的例子 fsockopen与HTTP 1.1/HTTP 1.0,再衍生出一些知识点。fsockopen 异步处理的第二个程序,就是制定标头为 HTTP 1.1的程序,当时程序输出是这样的:

    HTTP/1.1 200 OK
    Date: Sat, 08 Feb 2014 03:22:04 GMT
    Server: Apache/2.2.3 (CentOS)
    X-Powered-By: PHP/5.3.3
    Vary: Accept-Encoding
    Content-Length: 21
    Connection: close
    Content-Type: text/html; charset=UTF-8
    
    Welcome to NowaMagic 
    

    我们换个使用 Nginx 的服务器再执行看看:

    function asyn_sendmail()
    {
    	$hostname = 'www.nowamagic.net';
        $url = '/sock.php';
        $fp = fsockopen($hostname, 80, $errno, $errstr, 5);
        if (!$fp)
        {
            echo "$errstr ($errno)//<br />\n";
        }
    
        $end = "\r\n";
        $input = "GET $url HTTP/1.1$end";
        //如果不加下面这一句,会返回一个http400错误       
    	$input.="Host: $hostname$end";    
    	//如果不加下面这一句,请求会阻塞很久      
    	$input.="Connection: Close$end";     $input.="$end";
        fputs($fp, $input);
        $html = '';
        while (!feof($fp))
        {
            $html.=fgets($fp);
        }
        fclose($fp);
        writelog($html);
        echo $html;
    }
    
    function writelog($message)
    {
        $path = 'F:\log.txt';
        $handler = fopen($path, 'w+b');
        if ($handler)
        {
            $success = fwrite($handler, $message);
            fclose($handler);
        }
    }
    asyn_sendmail();
    

    程序输出:

    HTTP/1.1 200 OK
    Server: nginx/1.4.2
    Date: Sat, 08 Feb 2014 03:51:26 GMT
    Content-Type: text/html
    Transfer-Encoding: chunked
    Connection: close
    X-Powered-By: PHP/5.3.6
    
    15
    Welcome to NowaMagic 
    0
    

    为什么输出包含 15,0之类奇怪的东西呢?

    注意到返回头中有这么一个声明:Transfer-Encoding: chunked,在 Apache 返回信息里的Content-lenght字段没有了。chunked 就是传输编码为分段方式传输。

    分块传输编码是一种机制,允许将HTTP消息分成几个部分传输。同时适用于HTTP请求(从客户端到服务器)和 HTTP响应(从服务器到客户端)。

    例如,让我们考虑HTTP服务器可将数据传输到客户端应用程序(通常是一个网络浏览器)使用哪些方式。通常情况下,在HTTP响应数据是按照一整块发送给客户端的,数据的长度是由Content - Length头域表示。数据的长度很重要,因为客户需要知道在哪里响应结束和后面的响应何时启动。而使用Chunked编码方式,不管怎样,数据都会分割成一系列的数据块和一个或多个转发的“块”,因此服务器在知道内容的长度之前,就可以开始发送数据后。通常情况下,这些数据块的大小是一样的,但也并不是绝对的。

    大概意思了解后,我们来看例子:

    Chunked编码使用若干个Chunk串连而成,由一个标明长度为0的chunk标示结束。每个Chunk分为头部和正文两部分,头部内容指定下一段正文的字符总数(十六进制的数字)和数量单位(一般不写),正文部分就是指定长度的实际内容,两部分之间用回车换行(CRLF)隔开。在最后一个长度为0的Chunk中的内容是称为footer的内容,是一些附加的Header信息(通常可以直接忽略)。具体的Chunk编码格式如下:

    HTTP/1.1 200 OK
    Server: nginx/1.4.2
    Date: Sat, 08 Feb 2014 03:51:26 GMT
    Content-Type: text/html
    Transfer-Encoding: chunked
    Connection: close
    X-Powered-By: PHP/5.3.6
    
    15
    // 这是第一段数据
    Welcome to NowaMagic 
    
    // 数据长的话还会出现第二段数据 
    
    // 结束
    0
    

    情况搞清楚了,那么我们怎么来解码这个编码后的数据呢?

    在php官方手册fsockopen函数下面的评论中,已经有很多人提出了解决方法。

    方法1:

    function unchunk($result) {
        return preg_replace_callback(
            '/(?:(?:\r\n|\n)|^)([0-9A-F]+)(?:\r\n|\n){1,2}(.*?)'.
            '((?:\r\n|\n)(?:[0-9A-F]+(?:\r\n|\n))|$)/si',
            create_function(
                '$matches',
                'return hexdec($matches[1]) == strlen($matches[2]) ? $matches[2] : $matches[0];'
            ),
            $result
        );
    }
    

    方法2:

    function unchunkHttp11($data) {
        $fp = 0;
        $outData = "";
        while ($fp < strlen($data)) {
            $rawnum = substr($data, $fp, strpos(substr($data, $fp), "\r\n") + 2);
            $num = hexdec(trim($rawnum));
            $fp += strlen($rawnum);
            $chunk = substr($data, $fp, $num);
            $outData .= $chunk;
            $fp += strlen($chunk);
        }
        return $outData;
    }
    

    注意:这两个函数的参数都是返回的http原始数据(包括头)

更多 推荐条目

Welcome to NowaMagic Academy!

现代魔法 推荐于 2013-02-27 10:23   

本章最新发布
随机专题
  1. [Python程序设计] Django数据库模型 6 个条目
  2. [PHP程序设计] 声明式编程范式 12 个条目
  3. [移动开发] Android与SQLite数据库 7 个条目
  4. [PHP程序设计] PHP与Stream流 5 个条目
  5. [C语言程序设计] 结构体基本知识 1 个条目
  6. [Python程序设计] Django 入门知识浅介 10 个条目
  7. [移动开发] 刷机与root相关 2 个条目
  8. [JavaScript程序设计] Web实时通信技术名词解析 5 个条目
  9. [PHP程序设计] PHP里的布尔类型 3 个条目
  10. [计算机算法] 两数交换的各种算法细节 2 个条目
  11. [PHP程序设计] Nginx基本操作释疑 7 个条目
  12. [软件工程与项目管理] 了解一点WebKit 9 个条目
窗口 -- [协会]