实时Web与WebSocket实践

为什么实时Web这么重要?我们生活在一个实时(real-time)的世界中,因此Web的最终最自然的状态也应当是实时的。用户需要实时的沟通、数据和搜索。我们对互联网信息实时性的要求也越来越高,如果信息或消息延时几分钟后才更新,简直让人无法忍受。现在很多大公司(如Google、Facebook和Twitter)已经开始关注实时Web,并提供了实时性服务。实时Web将是未来最热门的话题之一。

实时Web的发展历史

  传统的Web是基于HTTP的请求/响应模型的:客户端请求一个新页面,服务器将内容发送到客户端,客户端再请求另外一个页面时又要重新发送请求。后来有人提出了AJAX,AJAX使得页面的体验更加“动态”,可以在后台发起到服务器的请求。但是,如果服务器有更多数据需要推送到客户端,在页面加载完成后是无法实现直接将数据从服务器发送给客户端的。实时数据无法被“推送”给客户端。
  为了解决这个问题,有人提出了很多解决方案。最简单(暴力)的方案是用轮询:每隔一段时间都会向服务器请求新数据。这让用户感觉应用是实时的。实际上这会造成延时和性能问题,因为服务器每秒都要处理大量的连接请求,每次请求都会有TCP三次握手并附带HTTP的头信息。尽管现在很多应用仍在使用轮询,但这并不是最理想的解决方案。
  后来随着Comet技术的提出,又出现了很多更高级的解决方案。这些技术方案包括永久帧(forever frame)、XHR流(xhr-multipart)、htmlfile,以及长轮询。长轮询是指,客户端发起一个到服务器的XHR连接,这个连接永不关闭,对客户端来说连接始终是挂起状态。当服务器有新数据时,就会及时地将响应发送给客户端,接着再将连接关闭。然后重复整个过程,通过这种方式就实现了“服务器推”(server push)。
  Comet技术是非标准的hack技术,正因为此,浏览器端的兼容性就成了问题。首先,性能问题无法解决,向服务器发起的每个连接都带有完整的HTTP头信息,如果你的应用需要很低的延时,这将是一个棘手的问题。当然不是说Comet本身有问题,因为还没有其他替代方案前Comet是我们的唯一选择。
  浏览器插件(如Flash)和Java同样被用于实现服务器推。它们可以基于TCP直接和服务器建立socket连接,这种连接非常适合将实时数据推给客户端。问题是并不是所有的浏览器都安装了这些插件,而且它们常常被防火墙拦截,特别是在公司网络中。
  现在HTML5规范为我们准备了一个替代方案。但这个规范稍微有些超前,很多浏览器都还不支持,特别是IE,对于现在很多开发者来说帮助不大,鉴于大部分浏览器还未实现HTML5的WebSocket,现行最好的办法仍然是使用Comet。

WebSocket

  WebSocket(http://dev.w3.org/html5/websockets)是HTML5规范(http://www.w3.org/TR/html5)的一部分,提供了基于TCP的双向的、全双工的socket连接。这意味着服务器可以直接将数据推送给客户端,而不需要开发者求助于长轮询或插件来实现,这是一个很大的进步。尽管有一些浏览器实现了WebSocket,但由于一些安全问题没有解决,因此协议(http://goo.gl/F7lvW)仍然在修订之中。然而这不会阻碍我们的脚步,这些安全问题属于技术性问题,会很快被修复,WebSocket很快就会成为最终规范。与此同时,对于那些不支持WebSocket的浏览器,可以降级使用笨方法来实现,比如Comet或轮询。
  和之前的服务器推的技术相比,WebSocket有着巨大的优势,因为WebSocket是全双工的,而不是基于HTTP的,一旦建立连接就不会断掉。Comet所面对的现实问题就是HTTP的体积太大,每个请求都带有完整的HTTP头信息。而且包含很多没有用的TCP握手,因为HTTP是比TCP更高层次的网络协议。
  使用WebSocket时,一旦服务器和客户端之间完成握手,信息就可以畅通无阻地随意往来于两端,而不用附加那些无用的HTTP头信息。这极大地降低了带宽的占用,提高了性能。因为连接一直处于活动状态,服务器一旦有新数据要更新时就可以立即发送给客户端(不需要客户端先请求,服务器再响应了)。另外,连接是双工的,因此客户端同样可以发送数据给服务器,当然也不需要附带多余的HTTP头。
  下面这段话出自Google的Ian Hickson,HTML5规范小组负责人,它是这样描述WebSocket的:

将千字节的数据降为2字节……并将延时从150毫秒降为50毫秒,这种优化跨越了不止一个量级,实际上仅这两点优化就足以让Google确信WebSocket会给产品带来非一般的用户体验。

  现在我们来看一下都有哪些浏览器支持WebSocket:

Chrome >= 4
Safari >= 5
iOS >= 4.2
Firefox >= 4*
Opera >= 11*

  尽管Firefox和Opera也都实现了WebSocket,但考虑到WebSocket仍然存在安全隐患,默认并没有启用它。但这不是什么大问题,或许本书出版时WebSocket的安全问题就已经解决了。同时你也可以在那些对WebSocket支持不好的浏览器中进行降级处理,使用诸如Comet和Flash的笨方法。
  检测浏览器是否支持WebSocket也非常简单、直接:

varsupported=("WebSocket"inwindow);
if(supported)alert("WebSocketsaresupported");

  长远来看,浏览器的WebSocket API非常清晰且合乎逻辑。可以使用WebSocket类来实例化一个新的套接字(socket),这需要传入服务器的端地址,在这个例子中是ws://example.com:

var socket = new WebSocket("ws://example.com");

  然后我们需要给这个套接字添加事件监听 :

// 建立连接
socket.onopen = function(){ / ... / }

// 通过连接发送了一些新数据
socket.onmessage = function(data){ / ... / }

// 关闭连接
socket.onclose = function(){ / ... / }

  当服务器发送一些数据时,就会触发onmessage事件,同样,客户端也可以调用send()函数将数据传回服务器。很明显,我们应当在连接建立且触发了onopen事件之后调用它:

socket.onmessage=function(msg){
    console.log("Newdata-",msg);
};
socket.onopen=function(){
    socket.send("Why,hellothere").
};
发送和接收的消息只支持字符串格式。但在字符串和JSON数据之间可以很轻松地相互转换,这样就可以创建你自己的协议:
varrpc={
    test:function(arg1,arg2){/.../}
};
socket.onmessage=function(data){
    //解析JSON
    varmsg=JSON.parse(data);
    //调用RPC函数
    rpc[msg.method].apply(rpc,msg.args);
};

  这段代码中,我们创建了一个远程过程调用(remoteprocedurecall,RPC)脚本,服务器可以发送一些简单的JSON来调用客户端的函数,就像下面这行代码:

{"method":"test","args":[1,2]}

  注意,这里的调用是限制在rpc对象里的。这样做的原因主要是出于安全考虑,如果允许在客户端执行任意JavaScript代码,黑客就会利用这个漏洞。可以调用close()函数来关闭这个连接:

varsocket=newWebSocket("ws://localhost:8000/server");

  你肯定注意到了我们在实例化一个WebSocket的时候使用了WebSocket特有的协议前缀ws://,而不是http://。WebSocket同样支持加密的连接,这需要使用以wss://为协议前缀的TLS。默认情况下WebSocket使用80端口建立非加密的连接,使用443端口建立加密的连接。你可以通过给URL带上自定义端口来覆盖默认配置。要记住,并不是所有的端口都可以被客户端使用,一些非常规的端口很容易被防火墙拦截。
  说到现在,你或许会想,“我还不能在项目中使用WebSocket,因为标准还未成型,而且IE不支持WebSocket”。这样的想法并没有错,幸运的是,我们有解决方案。Web-socket-js是一个基于AdobeFlash实现的WebSocket。用这个库就可以在不支持WebSocket的浏览器中做优雅降级。毕竟几乎所有的浏览器都安装了Flash插件。基于Flash实现的SocketAPI和HTML5标准规范完全一样,因此当WebSocket的浏览器兼容性更好的时候,只需简单地将库移除即可,而不必对代码做任何修改。
  尽管客户端的API非常简洁、直接,但在服务器端情况就不同了。WebSocket协议包含两个互不兼容的草案协议:草案75和草案76。服务器需要通过检测客户端使用的连接握手类型来判断使用哪个草案协议。
  WebSocket首先向服务器发起一个HTTP“升级”(upgrade)请求。如果你的服务器支持WebSocket,则会执行WebSocket握手并初始化一个连接。“升级”请求中包含了原始域(请求所发出的域名)的信息。客户端可以和任意域名建立WebSocket连接,只有服务器才会决定哪些客户端可以和它建立连接,常用做法是将允许连接的域名做成白名单。
  在WebSocket的设计之初,设计者们希望只要初始连接使用了常用的端口和HTTP头字段,就可以和防火墙和代理软件和谐相处。然而理想是丰满的,现实是骨感的。有些代理软件对WebSocket的“升级”请求的头信息做了修改,打破了协议规则。事实上,协议草案的最近一次更新(版本76)也无意中打破了对反向代理和网关的兼容性。为了更好更成功地使用WebSocket,这里给出一些步骤:

  • 使用安全的WebSocket连接(wss)。代理软件不会对加密的连接胡乱篡改,此外你所发送的数据都是加密后的,不容易被他人窃取。
  • 在WebSocket服务器前面使用TCP负载均衡器,而不要使用HTTP负载均衡器,除非某个HTTP负载均衡器大肆宣扬自己支持WebSocket。
  • 不要假设浏览器支持WebSocket,虽然浏览器支持WebSocket只是时间问题。诚然,如果连接无法快速建立,则迅速优雅降级使用Comet和轮询的方式来处理。

那么,如何选择服务器端的解决方案呢?幸运的是,在很多语言中都实现了对WebSocket的支持,比如Ruby、Python和Java。要再次确认每个实现是否支持最新的76版协议草案,因为这个协议是被大多数客户端所支持的。

  • Node.js

─node-Websocket-server(http://github.com/miksago/node-websocket-server)
─Socket.IO(http://socket.io)

  • Ruby

─EventMachine(http://github.com/igrigorik/em-websocket)
─Cramp(https://github.com/lifo/cramp)
─Sunshowers(http://rainbows.rubyforge.org/sunshowers/)

  • Python

─Twisted(http://github.com/rlotun/txWebSocket)
─Apachemodule(http://code.google.com/p/pywebsocket)

  • PHP

─php-Websocket(http://github.com/nicokaiser/php-websocket)

  • Java

─Jetty(http://www.eclipse.org/jetty)

  • GoogleGo

─native(http://code.google.com/p/go)

  本文选自《基于MVC的JavaScript Web富应用开发》,点此链接可在博文视点官网查看。
                       
                     
  想及时获得更多精彩文章,可在微信中搜索“博文视点”或者扫描下方二维码并关注。
                        

时间: 2024-11-08 18:25:50

实时Web与WebSocket实践的相关文章

使用 HTML5 WebSocket 构建实时 Web 应用

在 IBM Bluemix 云平台上开发并部署您的下一个应用. 开始您的试用 作为下一代的 Web 标准,HTML5 拥有许多引人注目的新特性,如 Canvas.本地存储.多媒体编程接口.WebSocket 等等.这其中有"Web 的 TCP "之称的 WebSocket 格外吸引开发人员的注意.WebSocket 的出现使得浏览器提供对 Socket 的支持成为可能,从而在浏览器和服务器之间提供了一个基于 TCP 连接的双向通道.Web 开发人员可以非常方便地使用 WebSocket

实时Web不只是时尚 更是技术趋势

随着社会化互联网热潮的到来,实时web越来越受到大家的重视.一方面从业务场景角度而言,消息实时通知大大提高了系统的友好性:另一方面从性能角度而言,新数据由服务端自动推送,而非用户自动刷新页面获取,大大减轻了服务器压力. 国外媒体近日发表文章称,实时Web并不只是一种时尚,而是一种技术趋势.将来,实时技术将成为一种默认技术,也将越来越平民化,不是只有谷歌.Facebook和Twitter这种大咖才能玩得起. 以下为文章内容摘要: 实时Web并不只是一种时尚,而是一种技术转移--即时访问Web. 实

行为、审计日志 (实时索引/实时搜索)建模 - 最佳实践 2

标签 PostgreSQL , ES , 搜索引擎 , 全文检索 , 日志分析 , 倒排索引 , 优化 , 分区 , 分片 , 审计日志 , 行为日志 , schemaless 背景 在很多系统中会记录用户的行为日志,行为日志包括浏览行为.社交行为.操作行为等. 典型的应用例如:数据库的SQL审计.企业内部的堡垒机(行为审计)等. 前面写了一篇最佳实践,通过PostgreSQL来存储审计日志,同时对审计日志需要检索的字段建立全文索引. SSD机器可以达到7万/s的写入(换算成全文索引条目,约28

RESTful JSON Web服务最佳实践

本文讲的是RESTful JSON Web服务最佳实践,[IT168 资讯]Collaxa BPEL产品-后来成为Oracle SOA战略核心的一部分-背后的关键人物之一,Edwin Khodabakchian,已经单独致力于Feedly这一"将twitter和Google Reader编织成杂志一般的体验"的项目好几年了.最近Edwin发布了一本关于构建基于JSON的Web服务最佳实践的cookbook.当然这还在进行当中,但现有提供的指南包括了: 第一阶段-定义一个简单的资源/服务

Google Web开发最佳实践(二)

本指南逐步引导你使用 Web 新手开发包创建新站点,帮助你充分利用 Web 新手开发包提供的工具. 1.开发环境配置 本人环境为win7x64.需要安装以下环境. 安装NodeJS(同时会安装NPM): 安装Ruby(需要大于1.8.7版本),然后安装sass:gem install sass(楼主安装了好几次都提示连接错误,最终还是装上了...). 下载新手开发包:https://developers.google.com/web/starter-kit/,解压进入该目录,执行: npm in

web应用缓存实践

在当今互联网应用中,缓存作为一把尖刀利器对应用的性能起着举足轻重的作用.缓存的使用可以说无处不在,从应用请求的访问路径来看,用户user -> 浏览器缓存 -> 反向代理缓存-> WEB服务器缓存 -> 应用程序缓存 -> 数据库缓存等,几乎每条链路都充斥着缓存的使用,当然交换机,网络适配器,硬盘上也有Cache 但这不是我们要讨论的范围.今天我们讨论的"缓存",自然就是"用空间换时间"的算法.缓存就是把一些数据暂时存放于某些地方,可能

Google Web开发最佳实践(一)

这篇文章最初是在阿里通信前端团队的github博客(http://aliqin.github.io)上看到的,原文地址https://developers.google.com/web/fundamentals/(要翻墙).既然要去阿里了,就得先熟悉熟悉环境,既然是最佳实践,就得自己亲自实践一下. 1.创建网站的内容和结构 内容是任何网站最重要的部分.所以让我们为内容而设计,而不要让设计支配内容.在这个手册中,我们首先确定我们需要的内容,基于这个内容创建一个页面结构,然后在简单的线性布局里呈现页

携程基于Storm的实时大数据平台实践

  本文讲解了携程在实时数据平台的一些实践,按照时间顺序来说明我们是怎么一步一步构建起这个实时数据平台的,目前有一些什么新的尝试,未来的方向是怎么样的,希望对需要构建实时数据平台的公司和同学有所借鉴. 为什么要做实时数据平台 首先先介绍一下背景,为什么我们要做这个数据平台?其实了解携程的业务的话,就会知道携程的业务部门是非常多的,除了酒店和机票两大业务之外,有近20个SBU和公共部门,他们的业务形态差异较大,变化也快,原来那种Batch形式的数据处理方式已经很难满足各个业务数据获取和分析的需要,

JavaScript Web 应用最佳实践分析

[编者按]本文作者为 Mathias Schäfer,旨在回顾在客户端大量使用JavaScript 的最佳 Web应用实践.文章系国内 ITOM 管理平台 OneAPM 编译呈现. 对笔者来说,JavaScript 社区似乎已经陷入了一个时间扭曲隧道.我们现在进行的关于 JavaScript驱动(JavaScript-driven) Web 应用的讨论与2006年"Ajax"出现以及2012年JavaScript"单页应用"流行起来时的讨论如出一辙.只要我们站在巨人