php - fsockopen 连接在超时之前不会关闭

标签 php fgets fsockopen

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

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

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

没有成功,因为服务器返回一个 XML 字符串,并且只返回一个 XML 字符串(没有长度信息、eof、eol 等)。因此它将等到超时,显示接收到的 XML 和超时错误。我的问题类似于这个 dinosaur

简而言之,我想在套接字上读取 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 上发布了一些东西。

最佳答案

这段代码有几个问题:

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

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

关于php - fsockopen 连接在超时之前不会关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6573738/

相关文章:

php生成excel并下载

php - 在 wordpress 中使用 page-id 调用时不显示样式

关于 fgets() 函数字符限制的 C 编程?

c - 在 while 循环中, fgets() 以换行符作为输入自行运行

php - 我需要通过代理,(从正在运行的 fsockopen 代码获取远程视频文件的大小)

php - 从 Magento 中提取翻译短语

php 包括不在主机服务器上工作但在本地(xampp)服务器上工作

c - 如何从包含整数和字符串的文本文件中使用 fscanf 和 fgets?

php - 尝试使用 fsockopen() 连接 SSL 服务器

PHP fsockopen() 非常慢