当前位置:首页 > 技术文章 > php > fsockopen开打很慢的原因-完善DZ的dfopen函数
fsockopen开打很慢的原因-完善DZ的dfopen函数
文章来源:本站原创  浏览次数:1602  发布日期:2013-04-12
function dfopen($url, $post = '', $limit = 0,  $cookie = '', $bysocket = FALSE, $ip = '', $timeout = 15, $block = TRUE) { 
    $return = '';
    $uri = parse_url($url);
    $host = $uri['host'];
    $path = $uri['path'] ? $uri['path'].($uri['query'] ? '?'.$uri['query'] : '') : '/';
    $port = !empty($uri['port']) ? $uri['port'] : '';
    if(!$port){
        $port = ($uri['scheme'] == 'https') ? 80 : 80;
    }
    if($post) {//post请求
        $post = http_build_query($post);
        $out = "POST $path HTTP/1.0\r\n";
        $out .= "Accept: */*\r\n";
        //$out .= "Referer: $boardurl\r\n";
        $out .= "Accept-Language: zh-cn\r\n";
        $out .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $out .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";
        $out .= "Host: $host\r\n";
        $out .= 'Content-Length: '.strlen($post)."\r\n";
        $out .= "Connection: Close\r\n";
        $out .= "Cache-Control: no-cache\r\n";
        $out .= "Cookie: $cookie\r\n\r\n";
        $out .= $post;        
    } else {//get请求
        $out = "GET $path HTTP/1.0\r\n";
        $out .= "Accept: */*\r\n";
        //$out .= "Referer: $boardurl\r\n";
        $out .= "Accept-Language: zh-cn\r\n";
        $out .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";
        $out .= "Host: $host\r\n";
        $out .= "Connection: Close\r\n";
        $out .= "Cookie: $cookie\r\n\r\n";
    }
     
    $fp = @fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
    if(!$fp) {
        return false;//note $errstr : $errno \r\n
    } else {
        //集阻塞/非阻塞模式流,$block==true则应用流模式
        stream_set_blocking($fp, $block);
        //设置流的超时时间
        stream_set_timeout($fp, $timeout);
        @fwrite($fp, $out);
        //从封装协议文件指针中取得报头/元数据
        $status = stream_get_meta_data($fp);
 
        //timed_out如果在上次调用 fread() 或者 fgets() 中等待数据时流超时了则为 TRUE,下面判断为流没有超时的情况
        if(!$status['timed_out']) 
        {
            while (!feof($fp)) {
                $header = @fgets($fp);
                $findstr = 'Content-Length:';
                if(strpos($header, $findstr) !== false){//获取内容长度
                    $limit = intval(substr($header, strlen($findstr)));
                }
                if($header == "\r\n" ||  $header == "\n") {
                    break;
                }
            }
            $stop = false;
             
            //如果没有读到文件尾
            while(!feof($fp) && !$stop) {
                //看连接时限是否=0或者大于8192  =》8192  else =》limit  所读字节数
                $data = fread($fp, ($limit == 0 || $limit > 8192 ? 8192 : $limit));
                $return .= $data;
                if($limit) {
                    $limit -= strlen($data);
                    $stop = $limit <= 0;
                }
            }
        }
        @fclose($fp);
        return $return;
    }
}

业务需要,使用fsockopen模拟get/post的请求去获取数据,
在网上找了下封装好的方法,看DZ封装的那个函数还不错,就拿来使用了。代码如下:有的地方我修改过了


开始测试了一下,就是运行会很慢,需要10几秒的时间才能运行完毕。
但是用file_get_contents的话,很快就能取到数据。
排查了一下,应该是对方的服务器保持活动链接,然后又因为我取数据的时候用到了
!feof($fp),这个地方跟那个指定的获取的长度有关,也就是$limit,如果这个值越大,
他就会一直找下去,只到找到换行符。
最好的办法就是再加个获取内容长度的代码,这样就避免的长时间的等待。
修改的代码主要是这一块

while (!feof($fp)) {
    $header = @fgets($fp);
    $findstr = 'Content-Length:';
    if(strpos($header, $findstr) !== false){//获取内容长度
        $limit = intval(substr($header, strlen($findstr)));
    }
    if($header == "\r\n" ||  $header == "\n") {
        break;
    }
}


OK,好了。测试通过了。




















原文来自:fsockopen开打很慢的原因-完善DZ的dfopen函数 http://www.redyun.net/technology/80.html

红云案例Case