【问题标题】:Long polling - Message system长轮询 - 消息系统
【发布时间】:2013-03-22 12:34:47
【问题描述】:

我正在考虑使用 jQuery 和 PHP 为消息系统做一些长轮询。我很想知道实现这一目标的最佳/最有效的方法。我的基础是这个Simple Long Polling Example

如果用户正坐在收件箱页面上,我想拉入任何新消息。我看到的一个想法是在消息表中添加一个last_checked 列。 PHP 脚本看起来像这样:

query to check for all null `last_checked` messages
if there are any...
while(...) {
    add data to array
    update `last_checked` column to current time
}
send data back

我喜欢这个想法,但我想知道其他人对此有何看法。这是解决此问题的理想方法吗?任何信息都会有所帮助!

补充一点,网站上没有固定数量的用途,所以我正在寻找一种有效的方法。

【问题讨论】:

  • 这是个好问题,我正要问同样的问题。

标签: php long-polling


【解决方案1】:

是的,您描述它的方式是长轮询方法的一般工作方式。 您的示例代码有点模糊,所以我想补充一点,您应该在 while 循环内执行一小段时间 sleep() 并每次比较 last_checked 时间(存储在服务器端) 和current 时间(这是从客户端发送的)。

类似这样的:

$current = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
$last_checked = getLastCheckedTime(); //returns the last time db accessed

while( $last_checked <= $current) {
    usleep(100000);
    $last_checked = getLastCheckedTime();
}

$response = array();
$response['latestData'] = getLatestData() //fetches all the data you want based on time
$response['timestamp'] = $last_checked;
echo json_encode($response);    

在您的客户端 JS 中,您将拥有:

function longPolling(){
        $.ajax({
          type : 'Get',
          url  : 'data.php?timestamp=' + timestamp,
          async : true,
          cache : false,

          success : function(data) {
                var jsonData = eval('(' + data + ')');
                //do something with the data, eg display them
                timestamp  = jsonData['timestamp'];
                setTimeout('longPolling()', 1000);
          },
          error : function(XMLHttpRequest, textstatus, error) { 
                    alert(error);
                    setTimeout('longPolling()', 15000);
          }     
       });
}

【讨论】:

  • 欣赏答案!函数getLastCheckedTime 究竟包含什么?我知道你说它在最后一次访问数据库时返回,但我怎么知道?数据库中的一列?
  • 另外,我不应该在 if 语句中包含最后四行吗?
  • 是的,getLastCheckedTime(); 必须返回数据库中列的结果,当插入新消息时,该列将自动更新。最后四行不必在if 语句中,因为它们仅在新数据插入数据库时​​才会执行,因此while 仅在那时才中断。
【解决方案2】:

您可以添加为last_checked_time,而不是将新列添加为last_checked。这样就可以得到last_checked_timecurrent_time的数据了。

(i.e) DATA BETWEEN  `last_checked_time` AND `current_time`

【讨论】:

    【解决方案3】:

    如果您只有一个用户,那很好。如果你不这样做,你会遇到并发症。通过这样做,您还将运行大量的 SELECT 查询。

    一段时间以来,我一直坚信 PHP 和长轮询本身不能正常工作,因为 PHP 没有任何跨客户端事件驱动的可能性。这意味着您需要每 2 秒/5 秒检查一次数据库,而不是依赖事件。

    但是,如果您仍然想这样做,我会让您的消息传递系统在用户有消息时在目录中写入文件 [nameofuser].txt,并使用此触发器检查消息是否存在。如果文件存在且不为空,则触发获取消息、处理、反馈然后删除文本文件的请求。这将减少您的 SQL 开销,同时(如果您不小心的话)会增加您的磁盘 IO。

    在结构方面,关联表是迄今为止最好的。创建一个专门用于检查状态的新表,包含三列:user_idmessage_idread_at。用法应该很明显。没有的任何组合都是未读的。

    【讨论】:

      【解决方案4】:

      您可以创建一个名为:checked 的列,而不是创建名为 last_checked 的列。 如果将所有消息保存在数据库中,则可以更新数据库中的字段。示例:

      1. 用户 1 向用户 2 发送消息。
      2. PHP 使用长轮询系统接收消息并将消息保存在表格中。
      3. 用户 2 在线时会向服务器发送信号,通知服务器用户 1 已准备好接收消息
      4. 服务器检查表中所有未“检查”的消息并返回。

      【讨论】:

        猜你喜欢
        • 2013-03-28
        • 1970-01-01
        • 1970-01-01
        • 2013-01-19
        • 1970-01-01
        • 2013-08-13
        • 2014-02-01
        • 2013-07-28
        • 2015-09-05
        相关资源
        最近更新 更多