长轮询 - 消息系统

12

我正在研究使用 jQuery 和 PHP 进行长轮询以实现消息系统。我很好奇知道实现这一点的最佳/最有效方法是什么。我正在基于这个 简单的长轮询示例

如果用户正在收件箱页面上,我想拉取任何新消息。我看到的一个想法是在消息表中添加一个 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

我喜欢这个想法,但我想知道别人怎么想。这是一种理想的方法来处理这个问题吗?任何信息都会有所帮助!

此外,该网站上没有设置使用次数的限制,因此我正在寻找一种高效的方法来实现它。


这是个好问题,我也正想问同样的事情。 - samayo
4个回答

8
是的,你描述的方式通常是长轮询方法的工作方式。 你的示例代码有点模糊,因此我想补充说明,在while循环内应该使用sleep()来暂停一小段时间,并且每次比较服务器端存储的last_checked时间和客户端发送的current时间。 像这样: ``` while(True): time.sleep(1) if last_checked > current: # do something ```
$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 到底包含什么内容?我知道您说它返回最后一次访问数据库的时间,但是我应该如何判断呢?是数据库中的某一列吗? - SeanWM
另外,我最后四行代码是否不应该放在if语句中? - SeanWM
是的,getLastCheckedTime(); 必须返回数据库中一个列的结果,该列将在插入新消息时自动更新。 最后四行不必放在 if 语句中,因为它们只会在新数据插入到数据库时执行,因此 while 只有在那时才会中断。 - Vassilis Barzokas

2

不要将新列命名为 last_checked,而是应该命名为 last_checked_time。这样你就可以从 last_checked_timecurrent_time 获取数据。

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

1

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

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

1
如果您只有一个用户,那很好。如果不是,您将遇到复杂情况。这样做还会导致大量选择查询。
我一直坚信PHP和长轮询不能原生地工作,因为PHP没有任何跨客户端事件驱动的可能性。这意味着您需要每秒/2s/5s检查数据库,而不是依赖于事件。
然而,如果您仍然想这样做,我建议您的消息系统在用户收到消息时写入一个文件[namofuser].txt,并使用此触发器检查消息是否存在。如果文件存在且不为空,则发送请求以获取消息,处理,反馈,然后删除文本文件。这将减少您的SQL开销,同时(如果您不小心)增加磁盘IO。
在结构上,关联表是最好的。创建一个新的表专门用于检查状态,具有三列:user_id message_id read_at。用法应该很明显。任何不在其中的组合都未读。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接