长轮询/ HTTP流通用问题

我正在尝试使用php和jquery创建一个理论上的网络聊天应用程序,我已经阅读了有关长轮询和http流的内容,并且我设法应用了文章中介绍的大多数原则。 然而,有两个主要的事情我仍然无法理解。

随着长轮询

  • 服务器如何知道何时发送更新? 是否需要不断查询数据库,还是有更好的方法?

使用HTTP Streaming

  • 如何在Ajax连接期间检查结果是否仍然有效? 我知道jQuery的ajax调用的success函数,但是如何在连接仍在进行检查数据?

我会感激任何和所有的答案,谢谢你提前。

是的,类似彗星的技术通常会在一开始就炸毁大脑 – 只是让你以不同的方式思考。 另一个问题是没有那么多可用于PHP的资源,因为每个人都在使用node.js,Python,Java等进行Comet。

我会尽力回答你的问题,希望能为人们提供一些关于这个话题的信息。

服务器如何知道何时发送更新? 是否需要不断查询数据库,还是有更好的方法?

答案是:在最常见的情况下,您应该使用消息队列(MQ)。 RabbitMQ或Redis商店内置的Pub / Subfunction可能是一个不错的选择,尽管市场上有许多竞争解决方案,如ZeroMQ,Beanstalkd等。

因此,您可以只订阅 MQ事件而不是连续查询数据库,直到其他人发布您订阅的消息,MQ将唤醒您并发送消息。 聊天应用程序是一个非常好的用例来理解这个function。

另外我要提一下,如果您要搜索其他语言的Comet-chat实现,您可能会注意到不使用MQ的简单实现。 那么他们如何交换信息呢? 问题是这样的解决方案通常作为独立的单线程异步服务器实现,因此它们可以将所有连接存储在线程本地数组(或类似的东西)中,在单个循环中处理多个连接,只需选择一个并在需要时通知。 这种异步服务器实现是一种适合Comet-technique的现代方法。 但是你最有可能在mod_php或FastCGI之上实现你的Comet,在这种情况下,这个简单的方法对你来说不是一个选项,你应该使用MQ。

这对于理解如何实现独立的异步Comet服务器来处理单个线程中的多个连接仍然非常有用。 最新版本的PHP支持Libevent和Socket Streams,因此也可以在PHP中实现这种类型的服务器。 PHP文档中还有一个示例 。

如何在Ajax连接期间检查结果是否仍然有效? 我知道jQuery的ajax调用的成功函数,但是如何在连接仍在进行时检查数据?

如果你使用普通的Ajax技术(例如普通的XHR,jQuery Ajax等)进行长时间运行的民意调查,那么你就没有一种简单的方法可以在单个Ajax请求中传输多个响应。 正如你所提到的,你只有’成功’处理程序来处理整个响应,而不是它的部分。 作为一种解决方法,人们每个请求只发送一个响应并在“成功”处理程序中处理它,之后它们只是打开一个新的长轮询请求。 这就是HTTP协议的工作原理。

还应该提到的是,实际上存在使用各种技术来实现类似流的function的解决方法,这些技术使用诸如隐藏的IFRAME中的无限长页面或使用多部分HTTP响应之类的技术。 这两种方法都存在某些缺点(前一种方法被认为是不可靠的,有时会产生不必要的浏览器行为,例如无限加载指示符,后者会泄漏一致且直接的跨浏览器支持,但是某些应用程序仍然可以成功地依赖于当浏览器无法正确处理多部分响应时,机制回退到长轮询。

如果您希望以可靠的方式处理每个请求/连接的多个响应,则应考虑使用更高级的技术,例如最新浏览器或支持原始套接字的任何平台(如Flash或支持)的WebSocket。如果您为移动应用程序开发,例如)。

你能详细说明消息队列吗?

Message Queue是一个描述Observer模式 (也称为“Publish / Subscribe”或简称PubSub)的独立(或内置)实现的术语。 如果您开发一个大型应用程序,那么它就非常有用 – 它允许您分离系统的不同部分,实现事件驱动的异步设计,使您的生活更加轻松,尤其是在异构系统中。 它对现实系统有很多应用,我只提几个:

  • 任务队列。 假设我们正在编写自己的YouTube,需要在后台转换用户的video文件。 我们显然应该有一个带有UI的webapp来上传电影和一些固定数量的工作进程来转换video文件(也许我们甚至需要一些我们的工人才会离开的专用服务器)。 此外,我们可能不得不用C编写我们的工作人员以确保更好的性能。 我们所要做的就是设置一个消息队列服务器来收集和提供从webapp到我们的工作人员的video转换任务。 当工作者产生它时,它连接到MQ并空闲等待新任务。 当有人上传video文件时,webapp会连接到MQ并发布带有新作业的消息。 function强大的MQ(如RabbitMQ)可以在连接的工作人员中平均分配任务,跟踪已完成的任务,确保不会丢失任何内容,并提供故障转移甚至管理UI以浏览当前任务挂起和统计信息。
  • 异步行为。 我们的Comet-chat就是一个很好的例子。 显然我们不想定期轮询我们的数据库(那么Comet的用途是什么? – 做定期Ajax请求没什么大不同)。 当出现新的聊天消息时,我们宁愿有人通知我们。 而消息队列就是那个人。 假设我们正在使用Redis键/值存储 – 这是一个非常棒的工具,可以在其数据存储function中提供PubSub实现。 最简单的方案可能如下所示:
    1. 有人进入聊天室后,正在进行新的Ajax长轮询请求。
    2. 服务器端的请求处理程序向Redis发出命令以订阅“newmessage”通道。
    3. 一旦有人在他的聊天中输入消息,服务器端处理程序就会在Redis的“新消息”主题中发布消息。
    4. 发布消息后,Redis将立即通知所有订阅该频道的待处理处理程序。
    5. 在通知保持长轮询请求打开的PHP代码时,可以使用新的聊天消息返回请求,因此将通知所有用户。 他们可以在那时从数据库中读取新消息,或者消息可以直接在消息有效负载内传输。

我希望我的插图很容易理解,但是消息队列是一个非常广泛的主题,因此请参考上面提到的资源以便进一步阅读。

如何在Ajax连接期间检查结果是否仍然有效? 我知道jQuery的ajax调用的成功函数,但是如何在连接仍在进行时检查数据?

实际上,你可以。 我已经为上述内容提供了修改后的答案,但我不知道它是否仍在等待或被忽略。 在此提供更新,以便提供正确的信息。

如果保持客户端和服务器之间的连接打开,则可以推送通过其附加到响应的更新。 每次更新都会在XMLHttpRequest.onreadystatechange事件中被触发,并且XMLHttpRequest.onreadystatechange的值将为3.这意味着XMLHttpRequest.responseText继续增长。

你可以在这里看到一个例子: http : //www.leggetter.co.uk/stackoverflow/7213549/

要查看JS代码,只需查看源代码。 PHP代码是:

 > ' . $update_suffix; echo($message); flush(); $count = $count + 1; sleep($sleep_time); } ?> 

在基于Gecko的浏览器(如Firefox)中,可以使用multipart/x-mixed-replace完全替换responseText 。 我没有举例说明这一点。

使用jQuery.ajax看起来不可能实现相同类型的function。 每当触发onreadystatechange事件时,都不会触发success回调。 这是令人惊讶的,因为文档说明:

但是,没有提供onreadystatechange机制,因为成功,错误,完整和statusCode涵盖了所有可能的要求。

所以文档可能是错误的,除非我误解了它?

你可以在这里看到一个试图使用jQuery的例子: http : //www.leggetter.co.uk/stackoverflow/7213549/jquery.html

如果您查看Firebug或Chrome开发者工具中的网络选项卡,您会看到stream.php的文件大小在增长,但success回调仍然不是火。