我在写一个使用websocket的实时聊天应用程序。 我有一个函数,检查数据库中的特定用户的新消息。 我仍然缺少的是一种无限地调用此方法的方法,以便用户可以实时接收消息。PHP循环从数据库中提取
是否有一种方式来运行一个后台循环或类似的东西,可以做的伎俩?
谢谢
我在写一个使用websocket的实时聊天应用程序。 我有一个函数,检查数据库中的特定用户的新消息。 我仍然缺少的是一种无限地调用此方法的方法,以便用户可以实时接收消息。PHP循环从数据库中提取
是否有一种方式来运行一个后台循环或类似的东西,可以做的伎俩?
谢谢
,你可以做的最糟糕的事情是设置你所有的插座,以无阻塞。这将创建一个空闲循环,在那里你的WS服务器将不断检查所有内容,会吃掉你的CPU时间,完成任何有意义的事情,并让人们生气。
接下来最糟糕的事情是无限期阻止。这将要求客户定期发送数据,通过带宽咀嚼,完成任何有意义的事情,可能会在没有客户端连接的情况下将服务器置于挂起状态,并让人们生气。
而是使用阻塞,但设置超时。这是一个取决于你的系统的平衡行为,只有你可以决定超时的持续时间,希望用一些数据来支持你的决定。
放置暂停的最佳位置是socket_select()
。下面的代码将等待最多1秒钟的新数据包进入,当它变得无聊时,它会做你的数据库的东西。
define("SOCKET_TIMEOUT", 1);
function tick() { /* Put your DB checking here. */ }
while (true) {
$read = get_array_of_sockets_that_may_have_sent_a_packet();
$write = $except = null; // We probably don't care about these.
tick();
$number_of_sockets_ready = socket_select($read, $write, $except, SOCKET_TIMEOUT);
if ($number_of_sockets_ready === false) { ... } /* Something went horribly wrong. socket_strerror(socket_last_error()) is your friend here. */
elseif ($number_of_sockets > 0) {
// At least one socket is ready for socket_recv() or socket_read(). Do your magic here!
}
}
注意超时并不保证tick()
将被称为每秒,或每秒一次。如果数据包立即进入,并且处理起来很平常,那么在tick()
的调用之间可能只有几毫秒的时间。另一方面,如果有几个数据包进来,处理每个数据包都不是微不足道的,那么可能需要几秒钟才能再次调用tick()
。
伟大的工作,但它一次只检查一个用户的新邮件。我无法找到解决方案来检查连接的每个用户的数据库。 – michste93
@ michste93'socket_select()'将套接字句柄的数组作为参数,并通过引用修改该数组。当'socket_select()'返回时,您可以遍历数组中剩余的每个套接字句柄。 – Ghedipunk
重新阅读你的后续评论...你会在'tick()'期间检查数据库 - 没有什么神奇的,不需要'tick()'一次只处理一个连接/用户。您可能希望拥有一个保存与站点用户配对的活动WS连接的表,然后可以在连接和where子句中使用该表来将套接字句柄与具有等待通知的用户ID相匹配。 – Ghedipunk
我的首选方法是一种简单setTimeout()
调用多次检查新邮件服务器。
var checkForNewMessages = window.setTimeOut(function(){
$.ajax({
url: 'getChatUpdates.php',
type: 'POST',
data: {user_id: '<?php echo $_SESSION['user_id']; ?>' }
}).done(function(r){
// do stuff to display new messages here
});
}, 5000);
正如在评论中提到的,这取决于你的应用程序的架构,它可能是也可能不是一个安全问题有用户的ID在源代码中可见。如果是这样,另一种选择是为您的用户生成一次性唯一标识符。我个人不会,但正如我所说,这取决于您设置的架构。
不管怎样,在理论上,你可以生成从服务器端脚本一个GUID,并把它传递给你的AJAX,然后对Ajax使用GUID在它的下一个电话。 GUID会随着每次调用而改变,这样一个未经授权的人将无法简单地复制该Ajax请求。
一个更简单的方法可能是拿到从会话服务器端,而不是USER_ID传递它作为一个参数。
我从来没有建成这样的事我自己。但是如何编写一个轮询数据库的常规脚本,然后推送消息(理想情况下,这些应该是单独的组件),并设置一个计划任务,以您希望的频率运行此脚本。
架构上来说,这可能不是最优雅的解决方案,这也是你会发现人们争论围绕着类似的问题,争论及相关命题的位置:Invoking a PHP script from a MySQL trigger
但看到你如何问你的问题,有什么指示有关设置,这可能会做一个开始。
搜索服务器发送的事件 – Ahmad
你可以分享PHP以及数据库细节? –