一尘不染

长轮询/ HTTP流一般问题

php

我正在尝试使用phpjquery制作一个理论上的Web聊天应用程序,我已经阅读了有关长时间轮询和HTTP流的知识,并且设法运用了文章中介绍的大多数原理。但是,有两个主要问题我仍然无法解决。

长轮询

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

使用HTTP流

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

感谢您提供的所有答复。


阅读 427

收藏
2020-05-29

共1个答案

一尘不染

是的,类似彗星的技术通常在一开始会炸毁大脑-
只是让您以不同的方式思考。另一个问题是PHP没有足够的可用资源,因为每个人都使用node.js,Python,Java等编写Comet。

我将尽力回答您的问题,希望它能为人们阐明这个话题。

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

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

因此,您可以只 订阅 一个MQ事件并挂起,直到其他人将 发布
您订阅的消息,而MQ会唤醒您并发送消息,而不是连续查询数据库。聊天应用程序是了解此功能的一个很好的用例。

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

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

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

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

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

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

您能否详细说明消息队列?

Message
Queue
是一个术语,用于描述Observer模式的独立(或内置)实现(也称为“发布/订阅”或简称为PubSub)。如果您开发一个大型应用程序,那么拥有一个应用程序将
非常 有用-
它使您可以解耦系统的不同部分,实现事件驱动的异步设计,并使您的生活变得更加轻松,尤其是在异构系统中。它在现实世界的系统中有许多应用程序,我将仅提及其中的几个:

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

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

2020-05-29