PHP/JS 中从客户端到服务器的“心跳”

Posted

技术标签:

【中文标题】PHP/JS 中从客户端到服务器的“心跳”【英文标题】:"Heartbeats" from client to server in PHP/JS 【发布时间】:2012-03-03 23:56:33 【问题描述】:

我正在尝试创建一个允许用户“登录”和“注销”的小型 Web 应用程序。 我目前遇到的问题是允许客户端向服务器发送持续的“心跳”或消息以通知它仍然处于活动状态。

这更像是一个合乎逻辑的问题。我想要做的是在 php 中有一个 while(1) 循环来检查是否跳过了 n 个心跳。我仍然希望客户端和服务器能够在这个循环进行时进行交互(本质上我希望服务器表现得好像它有一个单独的“check_for_heartbeats”线程。

如何使用 php 实现这一点?我现在正在运行 XAMPP。任何帮助将不胜感激。

编辑:澄清一下,我想要做的是即使在 window.unload 事件不会触发的情况下(例如客户端与互联网断开连接),也能够捕获浏览器关闭事件。在这种情况下,有一个线程来监控心跳似乎是最直观的解决方案,尽管我不确定如何在 php.ini 中实现它。

编辑 2:isLoggedIn() 只是辅助函数,用于检查是否设置了会话布尔变量 ($_SESSION['is_logged_in'))。

最终编辑: 好的,我现在完全理解 cmets 和响应的意思了。因此,解释一下,这是潜在的解决方案: 有 javascript 代码向服务器发送“心跳”。服务器将添加与这些节拍关联的时间戳。 修改数据库以保存这些时间戳 查询整个“timestamps”表(更可能是具有“timestamp”属性的“users”表),并查看 NOW 和 last timestamps 之间的差异是否大于某个阈值。 “注销”任何超过此阈值的用户。

唯一的问题是如果只有一个用户登录,或者所有用户同时断开连接 - 但在这些情况下,没有其他人会看到用户断开连接。

这是多个响应的组合,但我认为克里斯的响应解决了大部分问题。感谢 chris 和 Alex Lunix 的有益贡献。 :D

这里有一个代码sn-p 更好的解释

服务器端:

function checkBeats()

    while(isLoggedIn())
    
        // it's been > 30 secs since last heartbeat
        if((time() - $_SESSION['heartbeat']) > 30)
        
            logout();
            break;
        
    

【问题讨论】:

不确定。我认为是的,因为我希望能够捕获诸如用户浏览器崩溃之类的问题(在这种情况下,不会触发 window.onbeforeunload 事件,并且我除了发出 ajax 请求的心跳之外什么都没有)。跨度> 我仍然很困惑你需要这个做什么。确保用户仍然登录的目标是什么?为什么你不能在他们每次发出请求时检查一下,并记录最后一次请求时间作为活动的衡量标准? 很抱歉给您带来了困惑。是的,我想确保用户仍然登录。客户端的心跳(即来自 javascript 代码的 ajax 请求)允许我确保用户仍然在线,但是我在哪里进行实际的“检查”到确保他们没有离线?现在,我拥有它,以便在任何时候触发 window.unload 事件时,客户端都会发送一条 ajax 消息,说明窗口已关闭。每当触发 onload 事件时,客户端都会告诉服务器窗口已打开。现在,如果客户端的互联网连接失败了——服务器如何发现? php 在没有人访问页面的情况下不会做任何事情,因此为了检查心跳时间并将其设置为已注销,您需要另一种编程语言检查,或者您需要合并一个系统它会检查每个页面加载时的所有心跳时间,并希望人们访问的次数足以刷新数据库。 我只是希望数据库保持一致。如果用户失去互联网连接,服务器真的无法发现,因为不会发送心跳。如果我以您建议的方式实现它(这几乎就是我现在的做法),用户将在他/她的互联网断开连接的整个时间内显示“登录”,直到用户决定访问该页面再次。这主要对其他用户来说是个问题,他们可能正在寻找也“登录”的人,并且可能正在与看似已登录但实际上已失去联系的人交谈。 【参考方案1】:

我通常做的是使用 javascript (jQuery) 调用 php 文件并更新数据库或任何你喜欢的东西。这个问题可能会回答你的问题:Whats the easiest way to determine if a user is online? (PHP/mysql)

【讨论】:

感谢您的回复,但我认为我想做的是与建议的答案相反。我希望通过某种方式确保用户的心跳不会停止以处理用户失去连接、浏览器崩溃或不会触发 window.unload 事件以确保用户处于正常状态的任何其他情况'在数据库中不被视为“登录”。 如果我做对了,当用户关闭浏览器,甚至拔掉网线时,您不会直接收到通知? 您打算如何使用它?如何检查一个人是否已登录? (您的功能“isLoggedIn”)。我猜 facebook 正在按照我在链接中建议的方式进行操作(对于他们的实时聊天),就好像我有两个 facebook 帐户并且我在 2 台不同的计算机上登录一样,我仍然会在线显示大约 30 秒在我关闭第二台计算机后。为了让它更“活”,你必须更频繁地更新在线状态。 同意,我可以通过 window.onbeforeunload 事件和 window.onload 事件来捕捉用户有意关闭和打开窗口的事件。我在这些事件期间发布 ajax 帖子以通知服务器用户刚刚离开网页,但真正的问题源于服务器处理心跳以使其更加“活跃”。如何在服务器空间中启用无限循环(通过 php)——它将处理心跳监控——不会阻止其他服务器请求? 好吧,创建一个无限的 PHP 循环不是一个好主意。而且我不知道您将如何从单个 while 循环中获取所有用户的“心跳”,因为会话变量只有在用户获取页面时才能访问。您打算如何处理用户的“在线”状态?因为我真的不明白你为什么需要“注销();”用户。如果你设置了一个会话,它只会在他们关闭浏览器之前有效,浏览器会自动将他们注销。如果你有一个包含用户和时间戳的数据库,你可以每隔 x 秒运行一次 cronjob,然后对离线用户做任何你想做的事情!【参考方案2】:

您可以使用 ajax 对更改 heartbeats 会话变量的脚本进行检测,然后在每个脚本的顶部执行此检查(当然,将其放入函数并调用它):

// it's been > 30 secs since last heartbeat
if((time() - $_SESSION['heartbeat']) > 30)

    logout();

编辑: 如果您希望数据库立即反映该状态,而不是在他们下次访问该页面时,您将需要使用 MySQL。在不使用其他程序(例如 java 程序)来检查数据库的情况下,我唯一能想到的就是在每个页面的顶部添加它(当然是在一个被调用的函数中):

mysql_query("UPDATE `users` SET `loggedin`=0 WHERE heartbeat<".time()-30);

这将更新每个用户,这意味着登录值的准确性将由页面浏览频率设置。

【讨论】:

无需注销。如果用户离线,脚本将不会被调用。 关键是如果他们下次访问时没有得到心跳,他们需要重新登录,但您有权在此之前系统不会识别他们处于离线状态下次访问。 抱歉,缺乏理解,我发布了一个可能是您所指的编辑。感谢您的洞察力!

以上是关于PHP/JS 中从客户端到服务器的“心跳”的主要内容,如果未能解决你的问题,请参考以下文章

如何在socket编程的Tcp连接中实现心跳协议

Eureka常见的问题

心跳包 WPF Unity 数据库搭建

单元测试心跳功能

socket.io的心跳机制是怎么用的

Netty SpringBoot 整合长连接心跳机制