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