5

背景:我必须创建一个普通站点,该站点接受传入的已发布 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()的第二个参数)。

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

4

3 回答 3

2

该片段有几个问题:

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

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

于 2011-07-04T16:20:26.197 回答
0

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

while(true) {
    $char = fread($fp, 1);
    $xml .= $char;
    if (is_complete($xml)) {
         break;
    }
}
于 2011-07-04T16:08:25.280 回答
0

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

            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);
于 2014-04-03T11:32:34.617 回答