4

我正在阅读很多有关 HTML5 的内容,我特别喜欢 Web 套接字,因为它们促进了 Web 服务器和 Web 浏览器之间的双向通信。

但我们一直在阅读有关 chrome、opera、firefox、safari 为 html5 做准备的信息。哪个 Web 服务器已准备好使用 Web 套接字功能?我的意思是,截至今天,Web 服务器是否能够启动后续通信?Google自己的Appengine怎么样?

如何编写利用 Java 中此功能的示例 Web 应用程序?

4

2 回答 2

10

Web 服务器和浏览器之间的双向通信并不是什么新鲜事。如果您正在阅读的问题发布了新答案,Stack Overflow 今天就会这样做。使用现有技术实现套接字样式行为有几种不同的策略:

  • AJAX 短轮询:连接到服务器并询问是否有任何新消息。如果没有,请立即断开连接并在短时间内再次询问。当您不想让服务器打开大量长时间运行的空闲连接时,这很有用,但这意味着您将只能以轮询间隔的速度接收新消息,并且会产生建立一个每次轮询时都有新的 HTTP 连接。
  • AJAX 长轮询:连接到服务器并保持连接打开,直到有新消息可用。这使您可以快速传递新消息并减少 HTTP 连接频率,但会导致服务器上的空闲进程运行时间更长。
  • iframe 长轮询:与上面相同,只是使用隐藏的 iframe 而不是 XHR 对象。当您想要进行跨站点长轮询时,对于绕过同源策略很有用。
  • 插件:Flash 的 XMLSocket、Java 小程序等可用于为浏览器建立更接近于真正低级持久套接字的东西。

HTML5 套接字并没有真正改变可用的底层策略。大多数情况下,它们只是将已经使用的策略形式化,并允许明确识别持久连接,从而更智能地处理。假设您想向移动浏览器发送基于 Web 的推送消息。使用正常的长轮询,移动设备需要保持清醒以保持连接。使用 WebSockets,当移动设备想要进入睡眠状态时,它可以将连接移交给代理,当代理接收到新数据时,它可以唤醒设备并传回消息。

服务器端是敞开的。要实现短轮询应用程序的服务器端,您只需要某种按时间顺序排列的消息队列。当客户端连接时,他们可以将新消息移出队列,或者他们可以传递一个偏移量并读取任何比其偏移量更新的消息。

实施服务器端长轮询是您的选择开始缩小的地方。大多数 HTTP 服务器都是为短期请求而设计的:连接、请求资源,然后断开连接。如果 300 人在 10 分钟内访问您的网站,并且每个人需要 2 秒来连接和下载 HTTP 资源,那么您的服务器在任何给定时间平均会打开 1 个 HTTP 连接。使用长轮询应用程序,您会突然保持 300 倍的连接数。

如果您运行自己的专用服务器,您可能能够处理此问题,但在共享托管平台上,您可能会遇到资源限制,App Engine 也不例外。App Engine 旨在处理大量低延迟请求,例如短轮询。您可以在 App Engine 上实现长轮询,但这是不明智的;运行时间超过 30 秒的请求将被终止,长时间运行的进程将耗尽您的 CPU 配额。

App Engine 的解决方案是即将推出的 Channel API。通道 API 使用 Google 现有的强大 XMPP 基础架构实现长轮询。

Brett Bavar 和 Moishe Lettvin 在 Google I/O 的演讲中列出了使用模式,如下所示:

App Engine 应用程序在远程服务器上创建一个频道,并返回一个频道 ID,并将其传递给网络浏览器。

class MainPage(webapp.RequestHandler):

    def get(self):
        id = channel.create_channel(key)
        self.response.out.write(
            {'channel_id': id})

Web 浏览器通过 iframe 长轮询将通道 ID 传递给同一远程服务器以建立连接:

<script src='/_ah/channel/jsapi'></script>
<script>
  var channelID = '{{ channel_id }}';
  var channel =
    new goog.appengine.Channel(channelId);
  var socket = channel.open();
  socket.onmessage = function(evt) {
    alert(evt.data);
  }
</script>

当有趣的事情发生时,App Engine 应用可以向用户的频道推送消息,浏览器的长轮询请求会立即收到:

class OtherPage(webapp.RequestHandler):

    def get(self):
        # something happened
        channel.send_message(key, 'bar')
于 2010-07-08T15:27:17.990 回答
3

例如,Jetty 从版本 7 开始支持此功能:Jetty Websocket Server

Google App Engine 也有这方面的计划。他们甚至在 Google I/O 2010 上对此进行了演示,但尚未投入生产。见票 #377

于 2010-07-08T09:39:01.133 回答