【问题标题】:Fire-and-forget in PHPPHP 中的即发即弃
【发布时间】:2011-08-01 17:18:59
【问题描述】:

最终更新

似乎我确实犯了一个非常简单的错误。因为我已经有一个流实现,所以我不能开始从流中读取:D


我正在尝试在 PHP 中实现类似 即发即弃 的功能。

From php.net

<?php
ignore_user_abort(true);
header("Content-Length: 4");
header("Connection: Close");
echo "abcd";
flush();

sleep(5);    
echo "Text user should not see"; // because it should have terminated
?>

如果我使用浏览器打开脚本,这将有效。 (显示“abcd”)。 但如果我用file_get_contents 或一些 stream 库打开它,它会等待约 5 秒并显示第二个文本。

我正在使用 PHP 5.2.11 / Apache 2.0


更新

我似乎对我要完成的工作有些困惑。

我不想使用输出缓冲区隐藏输出(这很愚蠢)。我想让客户端在服务器启动一个可能很长的过程(sleep(5))之前终止,我不希望客户端等待它(这就是即发即弃的意思,排序)。 使用输出缓冲区只是一个副作用。我在不使用输出缓冲区的情况下修改了示例代码。

我不明白的是:为什么这个脚本在从浏览器访问它与在 PHP 中使用 file_get_contents("http://dev/test.php") 或一些 stream 库获取它时表现不同?我在测试中看到的是,例如 stream_get_contents 在返回任何输出之前实际上会阻塞 5 秒,这与我想要的完全相反。

更新2

更多结果:

  • 浏览器以某种方式响应flush()。我不知道如何在 PHP 中使用 streams 复制这种行为,我的流一直阻塞。
  • 我试过fread,发现它的行为类似于stream_get_contents
  • 指定 maxlength 无效,它仍会阻塞约 5 秒。
  • 更改阻塞模式没有任何效果(除了产生更多调用to stream_get_contents())。它会等待大约 5 秒,然后返回任何内容。
  • stream_set_read_buffer 无效(在 PHP 5.3.5 服务器上测试)

【问题讨论】:

  • 你想达到什么目的?如果您不想将最后的文本发送给客户端,为什么要将其输出给客户端?
  • 我认为你不应该使用ob_end_clean()ob_end_flush。选择一个。
  • @hakre 文本的打印就是一个例子。我真正想做的是开始一些过程,我不想让客户等待它。我认为“一劳永逸”将是一个众所周知的术语。
  • @hugo_leonardo,我已修改示例代码以不使用输出缓冲区。

标签: php stream fire-and-forget


【解决方案1】:

显示文本的第二部分是因为您正在使用 ob_end_flush()ob_end_clean() 停止输出缓冲。发生这种情况时,PHP 会正常输出内容。尝试以下方法:

<?php

ob_start(); // turn on output buffering
print "Text the user will see.";
ob_flush(); // send above output to the user and keep output buffering on

print "Text the user will never see";

ob_end_clean(); // empty the buffer and turn off output buffering. your script should end here.

?>

ob_end_clean() 出现在脚本末尾很重要。它清空缓冲区并且不将其内容发送给用户,从而将ob_flush() 之后的所有内容都隐藏起来。

【讨论】:

  • 您似乎误解了这个问题。我不想通过使用输出缓冲来隐藏输出,我希望客户端在服务器启动时终止,这是真正的任务。您提供的输出缓冲区示例不会导致客户端终止。
  • 如果是这种情况,输出缓冲是不适合这项工作的工具。我认为您需要调用一个单独的脚本(也许作为一个单独的进程)和 exit() 当前脚本。
【解决方案2】:

如何使用 file_get_contents 访问脚本?您如何使用浏览器访问它?如果你在没有“http://”的情况下访问脚本,当然它永远不会被执行。使用与浏览器中相同的 URL。

编辑:

浏览器甚至会在连接关闭之前呈现页面。即使您冲洗,我也不认为连接已关闭。您可以启动 Wireshark 并检查。 stream_get_contents 和 file_get_contents 将阻塞,直到它们有所有的输出。即使您冲洗,他们也无法确定没有更多内容。由于 content-length 标头似乎没有使 {file,stream}_get_contents 更早返回,因此您可能需要实现自己的缓冲,ala。 fopen,读取,fclose。

【讨论】:

  • 当然是 http://。我真的不介意“愚蠢”的问题,因为它们有时会暴露问题,但这有点冒犯。
  • 不要拿个人的东西。我只是想帮忙。我不知道你知道什么,不知道什么。我编辑了这个答案。告诉我你是否也考虑过我在那里写的东西。
  • 我用fread 的结果更新了我的帖子。我实际上不知道浏览器是否关闭连接,我只知道浏览器不再等待更多内容,我想要:D
【解决方案3】:

似乎我确实犯了一个非常简单的错误。由于我已经有一个流实现,我不能从流中开始读取:D

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多