长轮询/ HTTP流媒体一般问题

Mad*_*iha 19 php jquery comet long-polling http-streaming

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

随着长轮询

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

使用HTTP Streaming

  • 如何在Ajax连接期间检查结果是否仍处于活动状态?我知道jQuery的successajax调用函数,但是如何在连接仍在进行检查数据?

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

cof*_*ake 25

是的,类似彗星的技术通常会在一开始就炸毁大脑 - 只是让你以不同的方式思考.另一个问题是没有那么多可用于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文档中还有一个示例.

如何在Ajax连接期间检查结果是否仍处于活动状态?我知道jQuery的ajax调用的成功函数,但是如何在连接仍在进行时检查数据?

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

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

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

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

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

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

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


leg*_*ter 5

如何在Ajax连接期间检查结果是否仍处于活动状态?我知道jQuery的ajax调用的成功函数,但是如何在连接仍在进行时检查数据?

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

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

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

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

<?php
$updates = $_GET['updates'];
if(!$updates) {
  $updates = 100;
}

header('Content-type: text/plain');
echo str_pad('PADDING', 2048, '|PADDING'); // initial buffer required

$sleep_time = 1;
$count = 0;
$update_suffix = 'Just keep streaming, streaming, streaming. Just keep streaming.';
while($count < 100) {
  $message = $count . ' >> ' . $update_suffix;
  echo($message);
  flush();
  $count = $count + 1;
  sleep($sleep_time);
}
?>
Run Code Online (Sandbox Code Playgroud)

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

它看起来似乎不可能使用相同的功能jQuery.ajax.在success每次回调不会触发onreadystatechange事件.这是令人惊讶的,因为文档说明:

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

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

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

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