背景:
我正在制作一个PHP websocket服务器(here)作为DAEMON运行,其中显然有一个主循环侦听套接字连接和传入数据,所以我不能只用{创建一个其他循环{1}}因为它会冻结我的整个服务器。
我无法使用CRON作业执行外部脚本或者也可以分叉新进程(我猜)因为我必须在我的服务器类范围内将数据发送到连接的客户端套接字。
有没有人知道在PHP中实现这个的神奇技巧? :/
一些疯狂的想法:
sleep(x_number_of_seconds);
跟踪最后一个循环执行时间,并将其与每个循环的当前时间进行比较,如果它是我所需的X秒间隔,则执行方法...这将导致非常醉酒和不一致的间隔循环。microtime(true)
,通过websocket与我的服务器通信并告诉它执行我的方法......我说他们疯狂的想法!关于我正在努力实现的目标的其他信息:
我正在制作一个小型在线游戏(RPG之类),其中我想添加一些NPC,每隔X秒更新一次。
还有其他方法可以实现这一目标吗?我错过了什么吗?我应该在Node.js中重写我的服务器吗?
非常感谢您的帮助!
答案 0 :(得分: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);
}
}
基本上,如果自上次服务器tick后经过的时间大于或等于我想要的滴答间隔,则执行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替换你,你还是我的朋友。
答案 1 :(得分:0)
在我看来,你正在使用的websocket-framework太原始了,不允许你的服务器在等待来自客户端的连接时做其他有用的事情。对PHP的socket_select()函数的唯一调用被硬编码为一秒超时,并且当时间用完时它什么都不做。它真的应该允许回调或外部循环。
查看http://php.net/manual/en/function.socket-select.php手册页。最后一个参数是超时时间。 socket_select()等待套接字上的传入数据或直到超时时间结束,这听起来像你想要做的,但是库没有提供它。然后看看库如何在core / classes / SocketServer.php中使用它。
我假设你调用run()然后它就永远不会返回你的调用代码,直到它在socket上得到一条消息,这会阻止你做任何事情。