3

语境 :

我正在制作一个 PHP websocket 服务器(这里)作为一个 DAEMON 运行,其中显然有一个主循环监听套接字连接和传入数据,所以我不能只创建另一个循环,sleep(x_number_of_seconds);因为它会冻结我的整个服务器。

我无法使用 CRON 作业执行外部脚本或分叉一个新进程(我猜),因为我必须在我的服务器类的范围内才能将数据发送到连接的客户端套接字。

有谁知道在 PHP 中实现这一目标的魔术?:/

一些疯狂的想法:

  1. 用 跟踪最后一个循环执行时间microtime(true),并将其与每个循环的当前时间进行比较,如果它大约是我想要的 X 秒间隔,请执行该方法......这将导致一个非常醉且不一致的间隔循环。
  2. 在浏览器中运行 JavaScript setInterval(),它将通过 websocket 与我的服务器通信并告诉它执行我的方法......我说他们在哪里疯狂的想法!

有关我要实现的目标的其他信息:

我正在制作一个小型在线游戏(类似 RPG),我想在其中添加一些 NPC,每 X 秒更新一次他们的行为。

还有其他方法可以实现这一目标吗?我错过了什么吗?我应该用 Node.js 重写我的服务器吗?

非常感谢您的帮助 !

4

2 回答 2

2

一个完美的替代方案并不存在,所以我将使用我的疯狂解决方案#1:

$this->last_tick_time = microtime(true);
$this->tick_interval = 1;
$this->tick_counter = 0;

while(true)
{
    //loop code here...

    $t= microtime(true) - $this->last_tick_time;

    if($t>= $this->tick_interval)
    {
        $this->on_server_tick(++$this->tick_counter);
        $this->last_tick_time = microtime(true) - ($t- $this->tick_interval);
    }
}

基本上,如果自上次服务器滴答以来经过的时间大于或等于我想要的滴答间隔,则执行on_server_tick()方法。最重要的是:如果这一次发生得太晚,我们会减去时间溢出以使下一次滴答发生得更快。这样我们填补了空白,最后,如果socket_select超时设置为 1 秒,我们将永远不会有大于 1.99999999+ 秒的空白。

我还跟踪滴答计数器,这样我可以使用模 (%)在多个间隔上执行代码,如下所示:

protected function on_server_tick($counter)
{
    if($counter%5 == 0)
    {
        // 5 seconds interval
    }

    if($counter%10 == 0)
    {
        // 10 seconds interval
    }
}

这涵盖了我所有的需求!:D

别担心 PHP,我不会用 Node.js 代替你,你还是我的朋友。

于 2013-07-17T03:21:43.440 回答
0

在我看来,您使用的 websocket 框架过于原始,无法让您的服务器在等待来自客户端的连接时做其他有用的事情。对 PHP 的 socket_select() 函数的唯一调用被硬编码为一秒超时,当时间用完时它什么也不做。它确实应该允许回调或外部循环。

查看http://php.net/manual/en/function.socket-select.php手册页。最后一个参数是超时时间。socket_select() 等待套接字上的传入数据或直到超时时间结束,这听起来像是您想要做的,但库没有提供它。然后在 core/classes/SocketServer.php 中查看库是如何使用它的。

我假设你调用 run() 然后它永远不会返回到你的调用代码,直到它在套接字上收到一条消息,这会阻止你做任何事情。

于 2013-07-16T04:20:03.543 回答