“实时”数据更新背后隐藏着什么?深入解析实时技术
\n\n您是否曾好奇,聊天应用如何实现消息即时送达,或者股票行情如何自动刷新?传统的 HTTP 请求(浏览器向服务器发起请求,服务器响应)在此场景下显得缓慢且低效。我们需要 实时 技术的魔力。
\n\n在 Stack Overflow 上,“什么是 Long-Polling、Websockets、Server-Sent Events (SSE) 和 Comet?”这个问题获得了数千次浏览。这说明对这些术语感到困惑是很常见的。今天,我们将逐一梳理,编写真实的 PHP 代码,并理解何时使用哪种技术。
\n\n我们不会使用复杂的框架——仅使用纯 PHP 和几个流行的库。开始吧!
\n\n1. HTTP Polling(普通轮询)——技术之祖
\n\n在讨论高级技术之前,我们先回顾一下基础的 轮询。客户端(JavaScript)每隔 N 秒向服务器发送一次请求。服务器响应:“无新数据”或“这是数据”。
\n\nPHP 代码(服务器端):
\n<?php\n// polling_server.php\nheader('Content-Type: application/json');\n\n// 模拟获取数据\n$data = ['message' => 'Hello at ' . date('H:i:s')];\necho json_encode($data);\n\n\n客户端代码(JavaScript):
\nsetInterval(() => {\n fetch('polling_server.php')\n .then(response => response.json())\n .then(data => console.log(data.message));\n}, 3000); // 每 3 秒一次\n\n优点:简单。缺点:大量冗余请求,服务器负载高,延迟可达 N 秒。对于聊天应用来说,这不可接受。
\n\n2. Long-Polling——优雅的变通方案
\n\nLong-Polling 是轮询的改进版本。客户端发起一个 HTTP 请求,如果服务器没有数据,不会立即响应。它保持连接打开(处于等待状态)。一旦数据可用,服务器发送响应并关闭连接。客户端立即发起新的请求。
\n\n从客户端角度看,这是一个普通的 fetch。从服务器角度看,需要能够“休眠”并“唤醒”。
\n\nLong-Polling 的 PHP 示例
\n<?php\n// long_polling.php\nheader('Content-Type: application/json');\nheader('Cache-Control: no-cache');\n\n// 模拟等待新消息(例如,来自文件或数据库)\n$lastCheck = time();\n$timeout = 30; // 最长等待 30 秒\n\nwhile (time() - $lastCheck < $timeout) {\n // 检查是否有新数据\n $newData = checkForNewMessages(); // 您的函数\n if ($newData !== null) {\n echo json_encode(['status' => 'ok', 'data' => $newData]);\n exit;\n }\n // 休眠 1 秒,避免占用 CPU\n sleep(1);\n}\n\n// 如果 30 秒内无数据,返回空响应\necho json_encode(['status' => 'timeout', 'data' => null]);\n\n\n重要提示: 在实际项目中,将 sleep(1) 替换为 usleep(500000)(0.5 秒),并使用非阻塞检查(例如,对文件使用 filemtime(),或对数据库使用带超时的 SELECT ... FOR UPDATE)。
应用场景:旧式聊天、不支持 WebSockets 的网站通知。缺点:连接数量仍然很多,服务器资源消耗在“挂起”的请求上。
\n\n3. Server-Sent Events (SSE)——服务器到客户端的单向通道
\n\nSSE(Server-Sent Events) 是 HTML5 内置的技术。服务器可以随时向客户端发送数据,但仅限单向(服务器 → 客户端)。客户端使用 JavaScript 中的 EventSource。
\n\nSSE 非常适合:新闻推送、股票行情、日志、通知。
\n\nPHP 代码(服务器端):
\n<?php\n// sse_server.php\nheader('Content-Type: text/event-stream');\nheader('Cache-Control: no-cache'