php stream_get_contents挂在流的末尾 [英] php stream_get_contents hangs at the end of the stream

查看:119
本文介绍了php stream_get_contents挂在流的末尾的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题末尾的解决方案

我正在编写一个PHP应用程序,该应用程序将消息发送到服务器,然后使用stream_get_contents读回响应.我以相同的方式与Android应用中的同一服务器通信. android应用程序运行良好且响应迅速,但是从服务器读回响应时PHP挂起.

I am writing a PHP application that sends a message to a server and then reads a response back in using stream_get_contents. I communicate with the same server in an android app in the same way. The android app works fine and responds quickly, however the PHP hangs when reading the response back from the server.

在下面的代码示例中,我设置了5个字节的微小缓冲区来测试理论.如果删除此缓冲区大小,它将挂起,但是只有5字节大小时,它才挂在循环的最后一次传递上:

In the code sample below, I have set a tiny buffer size of 5 bytes to test a theory. If I remove this buffer size it hangs, however with the 5 byte size it only hangs on the last pass through the loop:

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

如您所见,最后两行之间有10s的延迟,而其他两行之间没有明显的延迟.

As you can see there is a 10s delay between the last two lines, but no noticeable delay between the others.

为您提供信息,我使用ETX标记(3)表示消息的结尾,因此,如果我单击此消息,也将停止,而不仅仅是流的结尾.

Also for your information I use an ETX marker (3) to signify the end of a message, so I also stop if I hit this rather than just the end of the stream.

我做错什么了吗?有更好的方法吗?

Am I doing something wrong? Is there a better way of doing this?

预先感谢...

需要明确的是,以上代码仅预期一个消息响应.它不关心接收到ETX字节后返回的任何数据.

Just to be clear, the above code is only expecting one message response. It does not care about any data that comes back after it has received an ETX byte.

Edit2:挂起已被看到长达40秒.似乎并没有固定为10秒,但是奇怪的是每次看起来都是不错的整数.

Hangs have been seen of up to 40 seconds now. It doesn't appear to be fixed to 10 seconds, but it weirdly seems to be nice round numbers every time.

解决方案(感谢chathux):

Solution (thanks to chathux):

stream_get_contents($stream, $bytes)将阻塞,直到接收到$bytes个字节或超时到期.这意味着我的代码快要结束了,试图读取5个字节(不存在),因此等待10秒钟才放弃.

stream_get_contents($stream, $bytes) will block until it receives $bytes bytes or the timeout expires. This means my code was reaching the end and trying to read 5 bytes (which didn't exist), it was therefore waiting 10s before giving up.

由于我知道返回给我的消息的最小大小为49个字节,因此我首先读取了这49个字节(阻塞直到获得它们或10s过期),以便填充stream_get_meta_dataunread_bytes字段.一旦有了这个,我就将缓冲区大小动态调整为min(16*1024, unread_bytes),因此我一次读取16k或读取所有剩余字节,以较小者为准.在我的情况下,这通常仅意味着两个循环,因为消息通常很小(49字节+有效负载).

As I know the minimum size of a message coming back to me is 49 bytes, I first read those 49 bytes (blocking until I get them or 10s expires) in order to populate the stream_get_meta_data's unread_bytes field. Once I have this I dynamically adjust the buffer size to min(16*1024, unread_bytes) so I either read 16k at a time or all of the remaining bytes, whichever is smaller. In my case this usually only means two goes through the loop as messages are often tiny (49 bytes + payload).

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

The system now hangs for approximately 3 seconds instead of 10, but it hangs waiting for the initial few bytes to arrive (rather than at the end) which can be put down to network latency and other normal factors.

推荐答案

文档说:"stream_get_contents()对已经打开的流资源进行操作,并以字符串形式返回剩余的内容,直到最大长度的字节,并从指定的偏移量开始. "

documentation says "stream_get_contents() operates on an already open stream resource and returns the remaining contents in a string, up to maxlength bytes and starting at the specified offset."

因此,当您提供5作为maxlength时,它将最多读取五个字节并继续.如果它无法读取5个字节 它会等待并在stream_set_timeout中提到的10秒后过期

so when you provide 5 as maxlength it will only read up to five bytes and continues. if it cant read up to 5 bytes it`ll wait and expires in 10 seconds which you have mentioned in stream_set_timeout

示例:

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

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

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

in above case server will wait till you write one more byte fwrite($client, "5");

这篇关于php stream_get_contents挂在流的末尾的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆