【问题标题】:False eof from feof() with sockets fgets来自带有套接字 fgets 的 feof() 的错误 eof
【发布时间】:2013-03-20 09:57:49
【问题描述】:

我继承了一段代码,它使用下面的 fetchURL() 函数从 url 中获取数据。我刚刚注意到,在检索到整页数据之前,它经常让feof() 返回 true。我尝试了一些测试,并使用file_get_contents()CURL 每次都检索整个页面。

错误是间歇性的。 在 9 次调用中,有时 7 次会成功完成,有时只会成功完成 4 次。9 个中的特定 4 个(它们是带有更改查询字符串的获取请求)总是成功完成。我尝试颠倒顺序请求和相同的 4 个查询字符串仍然始终成功,而其余的有时有效,有时无效。
因此,“似乎”返回的数据可能与问题有关,但让我感到困惑的是间歇性。在每种情况下返回的数据总是相同的(例如,每次我使用?SearchString=8502806 的查询字符串进行调用时,返回的页面都包含相同的数据),但有时整个页面由fgets/feof 提供,有时不是。

有人对可能导致这种情况的原因提出建议吗? O 在这个主题上看到的大多数其他帖子都是关于 feof() 没有返回 true 的相反问题。

function fetchURL( $url, $ret = 'body' ) {
    $url_parsed = parse_url($url);
    $host = $url_parsed["host"];
    $port = (isset($url_parsed["port"]))?$url_parsed["port"]:'';
    if ($port==0)
        $port = 80;
    $path = $url_parsed["path"];
    if ($url_parsed["query"] != "")
        $path .= "?".$url_parsed["query"];

    $out = "GET $path HTTP/1.0\r\nHost: $host\r\n\r\n";

    $fp = fsockopen($host, $port, $errno, $errstr, 30);

    fwrite($fp, $out);
    $body = false;
    $h = '';
    $b = '';
    while (!feof($fp)) {
        $s = fgets($fp, 1024);
        if ( $body )
            $b .= $s;
        else
            $h .= $s;
        if ( $s == "\r\n" )
            $body = true;
    }

    fclose($fp);

    return ($ret == 'body')?$b:(($ret == 'head')?$h:array($h, $b));
}

【问题讨论】:

  • feof 在套接字上通常(总是?)一个坏主意,因为它会等待服务器在继续之前实际关闭套接字。至少你也应该发送Connection: close 标头,但我强烈建议完全重写这段代码,因为它很糟糕(无意侮辱)。
  • 我正计划转换为 CURL,但我想知道可能导致我看到的问题的原因。因此问题。

标签: php fgets fsockopen feof


【解决方案1】:

对我来说这听起来像是一个超时问题。请参阅 PHP 手册中的 stream_set_timeout()

【讨论】:

  • 超时就像异常,如果出现问题,您应该使用它们来捕获错误,但不能正常使用。
  • @TomvanderWoerdt 从 Internet 获取数据时超时是不可避免的。这是对不可预测行为的合理解释,不是吗?
  • 是的,超时是不可避免的,但从问题来看,他没有遇到任何超时。绝对不是所有请求的 20%。
  • @TomvanderWoerdt 我同意这是一段不好的代码,但是由于正在更改的数据是查询字符串,因此远程主机在某些查询上花费的时间比其他查询更长是完全合理的。我就不多说了。
【解决方案2】:

我发现该代码有很多问题。

  • 永远不要在套接字上使用feof。它会一直挂起,直到服务器关闭套接字,这不一定会在收到页面后立即发生。
  • feof 可能会返回 true(套接字已关闭),而 PHP 的缓冲区中仍有一些数据。
  • 您将标头与正文区分开来的代码似乎依赖于 PHP 正常工作,这通常是个坏主意。 fgets 不一定读取一行,它也可以只返回一个字节(\r,然后下一次调用你可能会得到\n
  • 您没有正确编码路径值

为什么不直接将代码转换为使用 cURL 或 file_get_contents?

【讨论】:

  • 我正计划转换为 CURL,但我想知道可能导致我看到的问题的原因。因此问题。
猜你喜欢
  • 2013-01-03
  • 1970-01-01
  • 2017-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-31
  • 1970-01-01
相关资源
最近更新 更多