fsockopen 连接直到超时才关闭

发布于 2024-11-18 18:50:46 字数 1645 浏览 3 评论 0原文

背景: 我必须创建一个普通站点,它接受传入的发布的 XML 并通过套接字连接将 XML 发送到服务器,然后显示从服务器发回的 XML。简单易行。

问题: 我使用 fsockopen() 连接到服务器并发送 XML 没有任何问题。从服务器读取 XML 是一个全新的问题。正常的方法

while (!feof($fp)) {    
    echo fgets($fp);
}

并不能解决问题,因为服务器返回一个 XML 字符串,并且仅返回一个 XML 字符串(没有长度信息、eof、eol 等)。因此,它会等到超时,显示收到的 XML 和超时错误。我的问题与这个恐龙类似。

简而言之,我想读取套接字上的 XML,并在不再发送数据时立即关闭它(而不是等待超时)。将超时设置为较低值也不可行,因为服务器响应可能会在 2--30 秒之间变化。

解决方案: 经过一下午的挣扎,我决定分享以下这个问题的解决方案(欢迎批评)。

$fp = fsockopen("123.456.789.1", 80, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)";
} else {
    $wait = true;    
    $out = '<samplexml><item>something</item></samplexml>';

    // [1] disable blocking
    stream_set_blocking($fp, 0);
    fwrite($fp, $out);

    while (!feof($fp)) {
        $r = fgets($fp);
        echo $r;
        if (!strcmp($r, "")){                
            if (!$wait) {
                // [2] has recieved data on this socket before
                break;
            }
        } else {
            $wait = false;
        }
    }
    fclose($fp);
}

事实证明,我的主要问题是阻塞。因此,首先,[1]我必须禁用stream_set_blocking,以便fgets()可以连续检查新数据是否可用。如果不禁用,fgets() 将从服务器获取 XML,然后循环将在第二次尝试时卡住,因为它将等待更多数据可用(这永远不会)。

我知道,一旦我们读取了一些数据,如果返回任何空的 fgets() ,我们就可以立即关闭连接(因此我们仍然可以设置 fgets()< /em> 如果有必要)。

使用这个网站几个月后,我终于在 stackoverflow 上发布了一些东西。

Background:
I have to create a plain site that accepts incoming posted XML and sends the XML to a server via a socket connection and in turn display the XML sent back from the server. Easy peasy.

Problem:
I had no problem utilising fsockopen() to connect to the server and sending the XML. Reading the XML from the server was a whole new problem. The normal

while (!feof($fp)) {    
    echo fgets($fp);
}

did not do the trick, since the server returns one XML string, and one XML string only (no length information, eof, eol, etc.). Thus it would wait until the timeout was hit, display the received XML and a timeout error. My problem is similar to this dinosaur.

In a nutshell I want to read XML on the socket and close it as soon as no more data is being sent (not wait for timeout). Setting the timeout to a low value was also not viable as the server response can vary between 2--30 seconds.

Solution:
After struggling for the entire afternoon I decided to share the following solution for this problem (do criticise).

$fp = fsockopen("123.456.789.1", 80, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)";
} else {
    $wait = true;    
    $out = '<samplexml><item>something</item></samplexml>';

    // [1] disable blocking
    stream_set_blocking($fp, 0);
    fwrite($fp, $out);

    while (!feof($fp)) {
        $r = fgets($fp);
        echo $r;
        if (!strcmp($r, "")){                
            if (!$wait) {
                // [2] has recieved data on this socket before
                break;
            }
        } else {
            $wait = false;
        }
    }
    fclose($fp);
}

It turns out that my main problem was blocking. So first off, [1] I had to disable stream_set_blocking so that fgets() can continuously check if new data became available. If not disabled fgets() will get the XML from the server and then the loop will get stuck on the second try since it will wait until more data becomes available (which never will).

I know that as soon as we have read some data that we can immediatly close the connection if any empty fgets() are returned (thus we can still set the second parameter of fgets() if it should be necessary).

After using this site for months I finally got to post something on stackoverflow.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

鸩远一方 2024-11-25 18:50:46

该代码片段有几个问题:

  • 首先,比较 strcmp($r, "") 实际上没有意义。它有效,但没有意义。我认为 fgets 不会返回空字符串。如果没有更多可用数据,则返回FALSE。您的比较有效的原因是 FALSE 被转换为空字符串。但这会让你的代码不清晰。
  • 其次,由于流处于非阻塞模式,因此数据只能暂时不可用。通过在 fgets 返回 false 时中断循环,您可能只读取操作系统缓存的第一批数据。您尝试通过强制等待尚未收到数据来解决此问题,但这是一个脆弱的解决方案。
  • 最后,你忙循环等待数据。这是非常资源密集的。

最后两点可以通过使用 stream_select 来解决。通过这种方式,您可以强制执行较大的超时,直到收到第一个数据包,然后使用较小的超时。

The snippet has several problems:

  • First, the comparison strcmp($r, "") doesn't actually make sense. It works, but it doesn't make sense. I don't think fgets ever returns an empty string. If there is no more data available, it returns FALSE. The reason your comparison works is that FALSE is converted to an empty string. But it makes your code not clear.
  • Second, since you have the stream in non-blocking mode, data can be not available only temporarily. By breaking from the loop as soon as fgets returns false, you're potentially reading only the first batch of data that was cached by the OS. You try to work around this by forcing a wait no data has been received yet, but it's a brittle solution.
  • Finally, you busy loop waiting for the data. This is very resource intensive.

The two last points can be solved by using stream_select. This way you can enforce a large timeout until the first packet is received and then use a small timeout.

眉黛浅 2024-11-25 18:50:46

您可以使用 fread() 并一次提取一个字节。效率非常低,但您可以在响应到来时对其进行解析并检测 XML 何时结束,而无需等待连接超时。在 hacky 伪代码中:

while(true) {
    $char = fread($fp, 1);
    $xml .= $char;
    if (is_complete($xml)) {
         break;
    }
}

You could use fread() and pull in a single byte at a time. Very inefficient, but you could then parse the response as it comes and detect when the XML ends without having to wait for the connection to time out. In hacky pseudo-code:

while(true) {
    $char = fread($fp, 1);
    $xml .= $char;
    if (is_complete($xml)) {
         break;
    }
}
李白 2024-11-25 18:50:46

我用的是插座。我发送一个 xml 字符串,也收到一个 xml 字符串。当服务器向我发送字符串 '' 时,我必须关闭套接字。在下面你可以找到我的代码,如果这可以帮助某人:

            stream_set_blocking($fp, 0);
            fwrite($fp, $in);
            $result = '';

            while (!feof($fp)) {
                $r = fgets($fp);
                $result .= $r;
                //echo $r;
                if (strstr($r, "</response>") != null)
                    break;
            }
            fclose($fp);

I use the socket. I send a xml string and I receive a xml string too. When the server sends me the string '</response>', I must to close the socket. In the following you can find my code, if that can help someone:

            stream_set_blocking($fp, 0);
            fwrite($fp, $in);
            $result = '';

            while (!feof($fp)) {
                $r = fgets($fp);
                $result .= $r;
                //echo $r;
                if (strstr($r, "</response>") != null)
                    break;
            }
            fclose($fp);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文