是的,彗星式的技术通常在一开始就让大脑爆炸——只是让你以不同的方式思考。另一个问题是 PHP 可用的资源不多,因为每个人都在用 node.js、Python、Java 等做 Comet。
我会尝试回答你的问题,希望它可以为人们提供一些关于这个主题的信息。
服务器如何知道更新何时发送?是否需要不断查询数据库或有更好的方法?
答案是:在最一般的情况下,您应该使用消息队列 (MQ)。 RabbitMQ 或 Redis 存储中内置的 Pub/Sub 功能可能是一个不错的选择,尽管市场上有许多竞争解决方案,例如 ZeroMQ、Beanstalkd 等。
因此,您可以订阅 MQ 事件,而不是持续查询您的数据库,然后挂起,直到其他人发布您订阅的消息,MQ 将叫醒你并发送消息。聊天应用是理解此功能的一个很好的用例。
另外我必须提到,如果您要搜索其他语言的 Comet-chat 实现,您可能会注意到不使用 MQ 的简单实现。那么他们如何交换信息呢?问题是这样的解决方案通常被实现为独立的单线程异步服务器,因此它们可以将所有连接存储在线程本地数组(或类似的东西)中,在一个循环中处理多个连接,并在需要时选择一个并通知。这种异步服务器实现是一种非常适合 Comet-technique 的现代方法。但是,您很可能在 mod_php 或 FastCGI 之上实现 Comet,在这种情况下,这种简单的方法不适合您,您应该使用 MQ。
这对于理解如何实现一个独立的异步 Comet 服务器以在单个线程中处理多个连接仍然非常有用。最新版本的 PHP 支持 Libevent 和 Socket Streams,因此也可以在 PHP 中实现这种服务器。 PHP 文档中还有一个example。
如何在 Ajax 连接仍处于活动状态时检查结果?我知道 jQuery 对 ajax 调用的成功功能,但是如何在连接仍在进行时检查数据?
如果您使用普通的 Ajax 技术(例如普通 XHR、jQuery Ajax 等)进行长时间运行的轮询,则没有一种简单的方法可以在单个 Ajax 请求中传输多个响应。正如您所提到的,您只有“成功”处理程序来处理整个响应,而不是它的一部分。作为一种解决方法,人们每个请求只发送一个响应并在“成功”处理程序中处理它,之后他们只是打开一个新的长轮询请求。这就是 HTTP 协议的工作原理。
还应该提到的是,实际上有一些解决方法可以使用各种技术来实现类似流的功能,这些技术使用隐藏的IFRAME 中的无限长页面或使用多部分 HTTP 响应等技术。这两种方法都有一定的缺点(前一种被认为是不可靠的,有时可能会产生不必要的浏览器行为,例如无限加载指示器,而后一种会泄漏一致且直接的跨浏览器支持,但是已知某些应用程序仍然成功地依赖它当浏览器无法正确处理多部分响应时,机制会退回到长轮询)。
如果您想以可靠的方式处理每个请求/连接的多个响应,您应该考虑使用更先进的技术,例如 WebSocket,它受最新浏览器或任何支持原始套接字的平台(例如例如 Flash 或如果您为移动应用程序开发)。
您能否详细说明消息队列?
Message Queue 是一个描述Observer pattern(也称为“发布/订阅”或简称为 PubSub)的独立(或内置)实现的术语。如果您开发一个大型应用程序,拥有一个非常很有用 - 它允许您解耦系统的不同部分,实现事件驱动的异步设计并使您的生活更轻松,尤其是在异构系统中.它对现实世界的系统有很多应用,我只提几个:
- 任务队列。假设我们正在编写自己的 YouTube,并且需要在后台转换用户的视频文件。我们显然应该有一个带有 UI 的 web 应用程序来上传电影和一些固定数量的工作进程来转换视频文件(也许我们甚至需要一些专用服务器,我们的工作人员只会离开这些服务器)。此外,我们可能不得不用 C 编写我们的工人以确保更好的性能。我们所要做的只是设置一个消息队列服务器来收集来自 webapp 的视频转换任务并将其传递给我们的工作人员。当 worker 生成时,它连接到 MQ 并空闲等待新任务。当有人上传视频文件时,webapp 连接到 MQ 并发布一条带有新作业的消息。强大的 MQ,如RabbitMQ 可以在连接的工作人员之间平均分配任务,跟踪已完成的任务,确保不会丢失任何内容,并提供故障转移甚至管理 UI 来浏览当前待处理的任务和统计信息。
- 异步行为。我们的彗星聊天就是一个很好的例子。显然,我们不想一直定期轮询我们的数据库(那么 Comet 有什么用呢?——与定期 Ajax 请求没有太大区别)。我们宁愿需要有人在出现新的聊天消息时通知我们。消息队列就是那个人。假设我们正在使用Redis 键/值存储——这是一个非常棒的工具,它在其数据存储功能中提供了PubSub 实现。最简单的场景可能如下所示:
- 有人进入聊天室后,将发出新的 Ajax 长轮询请求。
- 服务器端的请求处理程序向 Redis 发出命令以订阅“newmessage”频道。
- 一旦有人在他的聊天中输入了一条消息,服务器端处理程序就会将一条消息发布到 Redis 的“newmessage”主题中。
- 发布消息后,Redis 将立即通知所有之前订阅该频道的待处理处理程序。
- 在通知保持长轮询请求打开的 PHP 代码时,可以使用新的聊天消息返回请求,因此将通知所有用户。他们可以在那时从数据库中读取新消息,或者这些消息可以直接在消息负载中传输。
我希望我的插图易于理解,但是消息队列是一个非常广泛的主题,因此请参阅上面提到的资源以进一步阅读。