【问题标题】:Read long-running PHP process client side读取长期运行的 PHP 进程客户端
【发布时间】:2016-03-12 02:35:03
【问题描述】:

我想读取一个长时间运行的 php 进程,该进程将在满足条件时返回数据。

根据我的研究,我遇到了:

  • 长轮询
  • 套接字(socket.io 和 node.js)
  • 棘轮

我正在努力理解和应用我的问题的实现。我在 PHP 中有以下循环:

public function store(ClientImpl $a)
{
    $request = \Illuminate\Support\Facades\Request::all();
    $originateMsg = new OriginateAction('Local/' . $request['agent'] . '@auto-answer');
    $originateMsg->setContext('G-Outgoing');
    $originateMsg->setPriority('1');
    $originateMsg->setExtension($request['dial']);
    $a->send($originateMsg);

    while(true) {
        if( $a->process() ) break;
        usleep(1000);
    }

    $a->close();

    echo 'OK';
    ob_end_flush();
    flush();
}

$a->process() 调用如下方法:

/**
 * Main processing loop. Also called from send(), you should call this in
 * your own application in order to continue reading events and responses
 * from ami. 
 */
public function process()
{
    $msgs = $this->getMessages();
    foreach ($msgs as $aMsg) {
        if ($this->_logger->isDebugEnabled()) {
            $this->_logger->debug(
                '------ Received: ------ ' . "\n" . $aMsg . "\n\n"
            );
        }
        $resPos = strpos($aMsg, 'Response:');
        $evePos = strpos($aMsg, 'Event:');
        if (($resPos !== false) && (($resPos < $evePos) || $evePos === false)) {
            $response = $this->_messageToResponse($aMsg);
            $this->_incomingQueue[$response->getActionId()] = $response;
        } else if ($evePos !== false) {
            $event = $this->_messageToEvent($aMsg);
            $response = $this->findResponse($event);
            if ($response === false || $response->isComplete()) {
                $this->dispatch($event);
            } else {
                $response->addEvent($event);
            }
        } else {
            // broken ami.. sending a response with events without
            // Event and ActionId
            $bMsg = 'Event: ResponseEvent' . "\r\n";
            $bMsg .= 'ActionId: ' . $this->_lastActionId . "\r\n" . $aMsg;
            $event = $this->_messageToEvent($bMsg);
            $response = $this->findResponse($event);
            $response->addEvent($event);
        }
        if ($this->_logger->isDebugEnabled()) {
            $this->_logger->debug('----------------');
        }
    }
}

$a-&gt;process() 然后堆叠事件消息,为了阅读这些消息,我创建了IEventListener 的实现,当调用$a-&gt;process() 时也称为“幕后”。

class VoipEventStart implements IEventListener
{
    public function handle(EventMessage $event)
    {
        $a = $event->getKeys();

        if( ($a['event'] == "Hangup" || $a['event'] == "HangupRequest") && strpos($a['channel'], 'SIP/') !== FALSE)
        {
            return true;
        }

        return false;
    }
}

process 方法在用户正在进行通话时从 Asterisk PBX 系统中读取事件。这意味着只要调用持续,流程循环就会持续。

如果浏览器看起来正在加载/等待,我将如何执行此客户端?

【问题讨论】:

  • 你的意思是简单的ajax吗?
  • $a->process() 是做什么的?它运行多长时间?它返回什么?
  • 我没有看到 process() 返回任何东西。但是当 process() 返回真值时,您示例中的循环会中断/停止。
  • @marekful 抱歉,我忘记添加课程了。 VoIPEventStart 在挂断时返回 true。
  • 我看到了你的更新。那么是否 process() 总是立即(或相对较快)返回 true 或 false 并且您想从客户端检测它何时返回 true 而不会阻止客户端代理?

标签: javascript php node.js socket.io ratchet


【解决方案1】:

您可以使用Server Sent Events 或一些套接字实现,但最简单的可能是长轮询策略就足够了。

为此,从客户端发送一个普通的 AJAX 请求并让服务器仅在满足条件时返回。它可以像更改服务器端代码一样简单,如下所示:

while(true) {
    if( $a->process() ) break;
    usleep(1000);
}
echo 'OK';
ob_end_flush();
flush();

并且客户端应该向启动上述循环的 PHP 文件发送一个简单的 GET 请求。这样,当响应返回此请求时,您就知道 process() 返回 true。

客户端代码可能如下所示:

<div>Call status: <span id="status">In call</span></div>
<script>
  $.get('/check_call_status.php?callerId=123', function(response) {
    if(response === 'OK') {
      $('#staus').html('finished');
    }
  });
</script>

当然,这可以更复杂地处理超时。例如。如果在给定时间段内对长轮询请求没有响应,请重新启动它 - 即中止请求并再次发送它以避免客户端或服务器超时。

【讨论】:

  • 我已经尝试过了,超时似乎是个大问题。如果调用持续时间超过超时时间,Ajax 调用将失败。我不能重新请求这个,因为它取决于 $a 的具体实现(请参阅更新的store 方法。)这意味着每次我重新请求时,我都会得到一个新的实现。你有什么建议?
  • 这听起来像是一个设计缺陷。呼叫者或现有呼叫必须有某种标识符。使用它,应该可以返回到事件状态检查器循环。如果调用不再存在(例如 $a->close() 被调用),您应该能够检测到并立即返回。
  • 中止 AJAX 请求将执行其 anobort 回调,因此它不应使用虚假信息更新客户端。使用长轮询在任何超时发生之前中止请求并立即重新启动它是一种很好的做法。
  • 抱歉回复晚了。这确实是一个设计缺陷,长轮询现在成功了。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多