用于在PHP中将事件从服务器推送到客户端的Websockets

时间:2014-01-15 15:54:27

标签: php multithreading events architecture websocket

我有一个场景,只要服务器上的某些内容发生变化,就必须更新webclient。为此,我在服务器端要么

  • 主动收集更改的无限循环
  • 一个回调,一个eventlistener,用一个eventloop挂钩到另一个系统/框架/类

当此机制发现更改或收到事件时,需要通过websocket将其传递给webclient。

虽然这很简单,例如在Java中,由于eventloops(线程),你有“运行应用程序”的概念,这不能很好地映射到PHP。 PHP旨在提供HTTP请求,本质上是无状态的。当一个请求进来时,PHP脚本被执行,做东西并呈现响应,然后解散为void。

如何运行服务器端PHP流程来监听事件,并为Web客户端提供与其打开websocket连接的方法?就像一个独立启动的线程,eventlisteners可以订阅?

我能想到的可能的解决方案:

场景A:PHP线程(pthreads)

如果使用PHP线程,它的工作原理是什么?

  • Webclient A提出请求
  • 在服务器端,启动新线程,保持websocket连接并进行侦听工作
  • “正常”响应/请求线程(产生事件修复线程的线程)在发回响应后结束
  • 客户端和服务器现已连接。客户端A现在在服务器上运行自己的线程
  • 当webclient B发出请求时,同样发生在他/她身上,从而创建一个新线程,可能与A中的第一个做同样的工作

情景B:CRON

要模拟eventloop,可以设置CRON作业以一定间隔运行PHP脚本。虽然这样做的目的是收集客户感兴趣的事件,但是如何掌握websocket端点?由于此PHP脚本独立于Web运行,如何将其加入开放(?)套接字?有人必须抓住他们......

如果PHP因为“脚本设计”而与websockets不匹配,那么什么是一个不错的选择?

1 个答案:

答案 0 :(得分:0)

Ratchet是一个很棒的php websocket服务器:http://socketo.me/

这就是我的所作所为:

$loop   = React\EventLoop\Factory::create();
$pusher = new MyApp\Pusher();

// run ratchet as a daemon @ 0.5 second intervals
$loop->addPeriodicTimer(0.50, function() use($pusher){
    //$thread = new AsyncThread\AsyncThread($pusher->clients); // Really wished this worked, but everytime i send a websocket resource to a thread the thread throws a fatal error if i attempt to bind the data and even if I dont the resource disappears /sigh
    $pusher->load(); // so I just call this function which basically handles each client one after the other as opposed to simultaneously via threads.
});

$webSock = new React\Socket\Server($loop);

if ($loop instanceof \React\EventLoop\LibEventLoop) {
    echo "\n HAS LibEvent"; // apparently performance is better with the libevent php extension callback installed; I haven't really noticed a significant difference
}

$webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
            new Ratchet\WebSocket\WsServer($pusher)
    ),
    $webSock
);

$loop->run();