php stream_get_contents在流的末尾挂起

时间:2013-12-19 14:53:01

标签: php sockets stream php-socket php-stream-wrappers

  

问题末尾的解决方案

我正在编写一个PHP应用程序,它将消息发送到服务器,然后使用stream_get_contents读取响应。我以相同的方式在Android应用程序中与同一服务器通信。 Android应用程序运行正常并快速响应,但是当从服务器读回响应时PHP挂起。

在下面的代码示例中,我设置了一个5字节的小缓冲区大小来测试理论。如果我删除了这个缓冲区大小,它会挂起,但是只有5字节大小,它只挂在最后一次循环中:

stream_set_timeout($this->socket, 10); //10 seconds read timeout

while (!feof($this->socket)) {
    $breakOut = false;

    echo 'Reading response'.time().'<br/>';
    $data = stream_get_contents($this->socket, 5);
    echo 'Read response'.time().'<br/>';

    if ($data === false) {
        $this->latestErrStr = "Timed out waiting for a response.";
        return false;
    } else {
        $index = strpos($data, chr(3));

        if ($index !== FALSE){
            $breakOut = true;
            $data = substr($data, 0, $index);
        }

        $response .= $data;
    }

    $stream_meta_data = stream_get_meta_data($this->socket);

    //If we have no EOF marker then break if there are no bytes left to read
    if($breakOut || $stream_meta_data['unread_bytes'] <= 0) {
        break;
    }
}

输出如下:

Reading response1387463602
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463603
Reading response1387463603
Read response1387463623

正如您所看到的,最后两行之间有10秒的延迟,但其他行之间没有明显的延迟。

另外,对于您的信息,我使用ETX标记(3)来表示消息的结束,所以如果我点击它而不仅仅是流的末尾,我也会停止。

我做错了吗?有没有更好的方法呢?

提前致谢...

编辑:为了清楚起见,上面的代码只期待一个消息响应。它不关心收到ETX字节后返回的任何数据。

Edit2:现在已经看到挂起长达40秒。它似乎没有固定为10秒,但每次看起来很奇怪的是圆形数字。

解决方案(感谢chathux)

stream_get_contents($stream, $bytes)将阻塞,直到收到$bytes个字节或超时到期为止。这意味着我的代码到达终点并尝试读取5个字节(不存在),因此在放弃之前等待10秒。

我知道回复给我的消息的最小大小是49字节,我首先读取这49个字节(阻塞直到我得到它们或10s到期)才能填充stream_get_meta_data'{{ 1}}字段。一旦我有了这个,我动态地将缓冲区大小调整为unread_bytes,所以我要么一次读取16k,要么读取所有剩余的字节,以较小者为准。在我的情况下,这通常只意味着两个通过循环,因为消息通常很小(49字节+有效负载)。

系统现在挂起大约3秒而不是10秒,但它会挂起等待最初的几个字节到达(而不是在结束时),这可以归结为网络延迟和其他正常因素。

2 个答案:

答案 0 :(得分:5)

文档说“stream_get_contents()对已经打开的流资源进行操作,并以字符串形式返回剩余的内容,最多为maxlength个字节,从指定的偏移量开始。”

所以当你提供5作为maxlength时,它最多只能读取5个字节并继续。如果它不能读取5个字节 它将等待并在10秒内到期,您在stream_set_timeout

中提到过

示例:

//server side statement<br/>
$data = stream_get_contents($this->socket, 5);

//corresponding client code<br/>
fwrite($client, "1234");

在上面的情况下服务器将等到你再写一个字节 fwrite($client, "5");

答案 1 :(得分:1)

我建议你只使用sleep($seconds)函数,甚至是usleep($nanoseconds)函数。 为流本身设置超时,而不是为每个stream_get_contents

设置超时