2015-08-28 157 views
1

我在写一个使用websocket的实时聊天应用程序。 我有一个函数,检查数据库中的特定用户的新消息。 我仍然缺少的是一种无限地调用此方法的方法,以便用户可以实时接收消息。PHP循环从数据库中提取

是否有一种方式来运行一个后台循环或类似的东西,可以做的伎俩?

谢谢

+0

搜索服务器发送的事件 – Ahmad

+0

你可以分享PHP以及数据库细节? –

回答

3

,你可以做的最糟糕的事情是设置你所有的插座,以无阻塞。这将创建一个空闲循环,在那里你的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()

+0

伟大的工作,但它一次只检查一个用户的新邮件。我无法找到解决方案来检查连接的每个用户的数据库。 – michste93

+0

@ michste93'socket_select()'将套接字句柄的数组作为参数,并通过引用修改该数组。当'socket_select()'返回时,您可以遍历数组中剩余的每个套接字句柄。 – Ghedipunk

+0

重新阅读你的后续评论...你会在'tick()'期间检查数据库 - 没有什么神奇的,不需要'tick()'一次只处理一个连接/用户。您可能希望拥有一个保存与站点用户配对的活动WS连接的表,然后可以在连接和where子句中使用该表来将套接字句柄与具有等待通知的用户ID相匹配。 – Ghedipunk

2

我的首选方法是一种简单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传递它作为一个参数。

+0

好的方法,但你的例子是非常冒险的(用user_id)。也许提供你的答案一些安全建议或至少一个警告。 – sanderbee

+0

@sanderbee,我可以看到这是没有必要的,但我不明白这可能是多么的有风险。无论如何,更新了我的答案。 –

+1

它不是它在代码中可见的部分,而是通过请求发送一个用户ID。任何人都可以将此号码从他自己的ID更改为其他人的ID,因此也请阅读他或她的所有消息。但无论如何,很好的编辑:) – sanderbee

0

我从来没有建成这样的事我自己。但是如何编写一个轮询数据库的常规脚本,然后推送消息(理想情况下,这些应该是单独的组件),并设置一个计划任务,以您希望的频率运行此脚本。

架构上来说,这可能不是最优雅的解决方案,这也是你会发现人们争论围绕着类似的问题,争论及相关命题的位置:Invoking a PHP script from a MySQL trigger

但看到你如何问你的问题,有什么指示有关设置,这可能会做一个开始。