如何在 facebookticker、meetup.com 主页等浏览器中显示持续的实时更新?在 python、PHP、node.js 中,服务器端的性能影响是什么?另外,如果页面由 akamai 之类的 CDN 缓存,我们如何实现相同的更新?
4 回答
您有两个选项(其他人在上面详细说明)。如果您不熟悉每个选项背后的一些概念性想法,我想我会给出一两行关于它们的信息。请注意,我在非常非常高的层次上介绍这些概念。
您的三个选项是:
- 短轮询
- 网络套接字
- 彗星/长轮询
短轮询
Short Polling通过强制客户端不断向服务器发送请求,克服了 Client-Server 之间的单向通信,形式如下:
Client: Do you have a message for me?
Server: No.
Client: (wait x seconds)
Client: Do you have a message for me?
Server: No.
Client: (wait x seconds)
Client: Do you have a message for me?
Server: Yes. Here it is!
Client: Yay!
Client: (update message)
代表客户的不断唠叨被称为轮询。为了实现这种结构,您需要将服务器设置为“监听”来自客户端的这些轮询请求。服务器还必须将这些消息存储在某个地方,以便在消息准备好时,服务器可以传递它们。在非常简单的级别上,您的服务器需要:
- 接受一般网络请求
- 接受轮询请求
- 运行获取消息的后台作业
- 将这些消息存储在某处,以便在轮询请求进入时,服务器可以检查它们。
您还需要将这些轮询请求与用户的某种会话 ID 联系起来,以便正确的消息到达正确的人。总体而言,范式很复杂,在我看来,效率低下。
网络套接字
Web Sockets 是 HTML5 的新功能。它们背后的基本思想是客户端可以保持与服务器的直接连接,并且它们可以相互推送信息。因此,与通常的做法不同:客户端发送 GET 请求>>服务器响应内容,Web Sockets 允许您保持持续对话。
但是,为了进行设置,您需要:
- 与 WebSocket 兼容的浏览器(并非全部都是)。
- 可以处理 Web 套接字的服务器(不确定如何表达这一点,但并非所有服务器都设置为这种安排)。
设置有点复杂,虽然比长轮询简单:
- 客户端保持与服务器的启用 Web 套接字的连接的连接
- 服务器通过 web socket 将结果推送给客户端
- 客户端根据结果更新页面
您会看到这种称为推送通知的模式(当然,如果您拥有 iPhone,您会经历过这种情况),因为服务器已被授权向客户端推送“东西”(多么不礼貌!)。由于有很多客户端和服务器的细微差别,我建议测试一下Pusher之类的东西,它基本上是一个 Web 服务,用于处理 Web Sockets 的所有困难部分。在开始自己设置之前,这将是您测试和使用该模式的一种简单方法。它同时具有客户端和服务器端库。
希望这些信息为您提供解决问题的基准。其他答案包含有关如何解决每种情况的更直接信息。
彗星/长轮询
Web Sockets 的另一种看似跨浏览器的方法是长轮询(参见Comet)。在这种情况下,您的客户端建立与服务器的连接并将其挂起,等待数据被推回。这个设置有点复杂,但它确实代表了Short Polling和Web Sockets之间的中间立场。
我建议使用 SockJS 或 Socket.io 作为客户端 JavaScript 库来实现类似套接字的连接,然后在服务器端使用 Tornado 将任何状态更改发布到客户端。代码相当简单。
客户端代码取决于您选择的库。SockJS 或 SocketIO。或者,如果您只想直接使用 Websockets,这非常简单:
update_socket = new WebSocket("ws://my_server.com/listening_url");
update_socket.onmessage = function (evt) {
$("#my_div").html(evt);
};
服务器端代码也很简单:
import tornado
class UpdateHandler(tornado.websocket.WebSocketHandler):
def open(self):
self.write_message('Hi client')
# listen for some events that are occurring
for message in function_that_generates_events():
self.write(message)
def on_message(self, message):
# Do something with incoming messages
def on_close(self):
# tidy up
app = tornado.web.Application(('r/listening_url',UpdateHandler))
app.listen(9000)
您可以使用轮询、长轮询或者如果您想要一个推送系统。最简单的就是民意调查。但是,所有解决方案都需要客户端编码。
性能影响取决于您的解决方案。最容易实施的是民意调查。一次短频率的轮询有效地执行一个请求,例如 100 毫秒或模拟实时。长轮询的影响较小,但它会在或多或少的时间内保持打开大量请求。