你的位置:首页 > Java教程

[Java教程]认识WebSocket理论篇


  本文转自http://www.ibm.com/developerworks/cn/java/j-lo-WebSocket/

  HTML5作为下一代WEB标准,拥有许多引人注目的新特性,如Canvas、本地存储、多媒体编程接口、WebSocket 等等。本文认识WebSocket理论部分主要介绍HTML5 WebSocket的由来和运行机制。在《认识WebSocket应用篇》会重点介绍服务端(基于Tomcat)及客户端(基于浏览器原生 HTML5 API)实现的详细步骤,并通过实际客户案例描述了客户端如何在 WebSocket 架构下使用 HTTP 长连接与服务器实现实时通信及消息推送的功能。

 

一、WebSocket技术的诞生背景

  在web应用中,其交互过程是客户端通过浏览器向服务器发出一个请求,服务器接收到请求后进行处理然后将结果返回给浏览器,浏览器解析结果并呈现信息给用户。随着互联网的快速发展,这种交互过程对于实时要求高、海量并发的Web应用有些力不从心。高并发与用户实时响应是 Web 应用经常面临的问题,这些应用常见的主要由社交网络的即时通讯、Web导航应用中的地理位置获取、金融证券的实时信息等。传统的请求-响应模式的Web开发处理这个问题时,通常采用的方案有:

  • 轮询:这是最早的一种实现实时 Web 应用的方案,客户端通过一定的时间间隔以频繁请求的方式向服务器发送请求,来保持客户端和服务器端的数据同步。这种方式一方面会有许多不必要的请求,而且浪费带宽。
  • 长轮询:是对定时轮询的改进和提高,目地是为了降低无效的网络传输。当服务器端没有数据更新的时候,连接会保持一段时间周期直到数据或状态改变或者 时间过期,通过这种机制来减少无效的客户端和服务器间的交互。当然,如果服务端的数据变更非常频繁的话,这种机制和定时轮询比较起来没有本质上的性能的提高。
  • 流技术:在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求。服务器端接到这个请求后作出回应并不断更新连接状态以保证客户端和服务 器端的连接不过期。通过这种机制可以将服务器端的信息源源不断地推向客户端。这种机制在用户体验上有一点问题,需要针对不同的浏览器设计不同的方案来改进 用户体验,同时这种机制在并发比较大的情况下,对服务器端的资源是一个极大的考验。

  上述方式其实并不是真正的实时技术,只是使用了一种技巧来实现的模拟实时。在每次客户端和服务器端交互的时候都是一次 HTTP 的请求和应答的过程,而每一次的 HTTP 请求和应答都带有完整的 HTTP 头信息,这就增加了每次传输的数据量。但这些方式最痛苦的是开发人员,因为不论客户端还是服务器端的实现都很复杂,为了模拟比较真实的实时效果,开发人员 往往需要构造两个HTTP连接来模拟客户端和服务器之间的双向通讯,一个连接用来处理客户端到服务器端的数据传输,一个连接用来处理服务器端到客户端的数据传输,这不可避免地增加了编程实现的复杂度,也增加了服务器端的负载,制约了应用系统的扩展性。

  • 基于Flash:AdobeFlash 通过自己的 Socket 实现完成数据交换,再利用 Flash 暴露出相应的接口为 JavaScript 调用,从而达到实时传输目的。此方式比轮询要高效,且因为 Flash 安装率高,应用场景比较广泛,但在移动互联网终端上 Flash 的支持并不好。IOS 系统中没有 Flash 的存在,在 Android 中虽然有 Flash 的支持,但实际的使用效果差强人意,且对移动设备的硬件配置要求较高。2012 年 Adobe 官方宣布不再支持 Android4.1+系统,宣告了 Flash 在移动终端上的死亡

  以上方式处理这些处理高并发及实时性需求的时候,会遇到难以逾越的瓶颈,需要的是一种高效节能的双向通信机制来保证数据的实时传输。在此背景下,基于 HTML5 规范的、有 Web TCP 之称的 WebSocket 应运而生。

  早期 HTML5 并没有形成业界统一的规范,各个浏览器和应用服务器厂商有着各异的类似实现,如 IBM 的 MQTT,Comet 开源框架等,直到 2014 年,HTML5 在 IBM、微软、Google 等巨头的推动和协作下正式从草案落实为实际标准规范,各个应用服务器及浏览器厂商逐步开始统一,在 JavaEE7 中也实现了 WebSocket 协议,从而无论是客户端还是服务端的 WebSocket 都已完备,可以查阅HTML5 规范获得最新的 HTML 协议规范及 WebSocket 支持。

 

二、WebSocket运行机制

  WebSocket 是 HTML5 一种新的协议。本质是先通过HTTP/HTTPS协议进行握手后创建一个用于交换数据的TCP连接,它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 存在不同,这主要包括两个方面,一是WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;二是WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信,下面左图是传统HTTP响应客户端服务器交互图,右图是WebSocket 模式客户端与服务器的交互图。

  

  由上,相对于传统 HTTP 每次请求-应答都需要客户端与服务端建立连接的模式,WebSocket 是类似 Socket 的 TCP 长连接的通讯模式,一旦 WebSocket 连接建立后,后续数据都以帧序列的形式传输。在客户端断开 WebSocket 连接或 Server 端断掉连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,且客户端发送和接受消息是在同一个持久连接上发起,实时性强。

  客户端和服务端交互的报文方面WebSocket 通讯与传统 HTTP 也是不同的。在客户端,new WebSocket 实例化一个新的 WebSocket 客户端对象,连接类似 ws://ip:port/path 的服务端 WebSocket URL,WebSocket 客户端对象会自动解析并识别为 WebSocket 请求,从而连接服务端端口,执行双方握手过程,客户端发送数据格式类似:

  WebSocket客户端连接报文: 

GET /webfin/websocket/ HTTP/1.1Host: localhostUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==Origin: http://localhost:8080Sec-WebSocket-Version: 13

  客户端发起的 WebSocket 连接报文类似传统 HTTP 报文,”Upgrade:websocket”参数值表明这是 WebSocket 类型请求,这个请求的目的就是要将客户端和服务器端的通讯协议从 HTTP 协议升级到 WebSocket 协议。“Sec-WebSocket-Key”是 WebSocket 客户端发送的一个 base64 编码的密文,要求服务端必须返回一个对应加密的“Sec-WebSocket-Accept”应答,否则客户端会抛出“Error during WebSocket handshake”错误,并关闭连接。

  服务端收到报文后返回的数据格式类似:

HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=

  "Sec-WebSocket-Accept”的值是服务端采用与客户端一致的密钥计算出来后返回客户端的,“HTTP/1.1 101 Switching Protocols”表示服务端接受 WebSocket 协议的客户端连接,经过这样的请求-响应处理后,客户端服务端的 WebSocket 连接握手成功, 后续就可以进行 TCP 通讯。在开发方面,WebSocket API 相对简单,只需要实例化 WebSocket,创建连接,然后服务端和客户端就可以相互发送和响应消息。

三、WebSocket实现

  WebSocket 的实现分为客户端和服务端两部分,客户端(通常为浏览器)发出 WebSocket 连接请求,服务端响应,实现类似 TCP 握手的动作,从而在浏览器客户端和 WebSocket 服务端之间形成一条 HTTP 长连接快速通道。两者之间后续进行直接的数据互相传送,不再需要发起连接和相应。

  • WebSocket服务端API

   WebSocket 服务端在各个主流应用服务器厂商中已基本获得符合 JEE JSR356 标准规范 API 的支持(详见JSR356 WebSocket API 规范),以下列举了部分常见的商用及开源应用服务器对 WebSocket Server 端的支持情况:

厂商应用服务器备注
IBMWebSphereWebSphere 8.0 以上版本支持,7.X 之前版本结合 MQTT 支持类似的 HTTP 长连接
甲骨文WebLogicWebLogic 12c 支持,11g 及 10g 版本通过 HTTP Publish 支持类似的 HTTP 长连接
微软IISIIS 7.0+支持
ApacheTomcatTomcat 7.0.5+支持,7.0.2X 及 7.0.3X 通过自定义 API 支持
 JettyJetty 7.0+支持

 

 

 

 

 

 

 

  服务器端需要我们自己来实现,目前市场上开源的实现也比较多。如:   

  1. Kaazing WebSocket Gateway(一个 Java 实现的 WebSocket Server);   
  2. mod_pywebsocket(一个 Python 实现的 WebSocket Server);   
  3. Netty(一个 Java 实现的网络框架其中包括了对 WebSocket 的支持);   
  4. node.js(一个 Server 端的 JavaScript 框架提供了对 WebSocket 的支持);   
  5. WebSocket4Net(一个.net的服务器端实现);

 

WebSocket客户端API 

  对于 WebSocket 客户端,主流的浏览器(包括 PC 和移动终端)现已都支持标准的 HTML5 的 WebSocket API,这意味着客户端的 WebSocket JavaScirpt 脚本具备良好的一致性和跨平台特性,以下列举了常见的浏览器厂商对 WebSocket 的支持情况:

浏览器支持情况
ChromeChrome version 4+支持
FirefoxFirefox version 5+支持
IEIE version 10+支持
SafariIOS 5+支持
Android BrowerAndroid 4.5+支持

 

 

 

 

 

  

  

  客户端 WebSocket API 基本上已经在各个主流浏览器厂商中实现了统一,因此使用标准 HTML5 定义的 WebSocket 客户端的 JavaScript API 即可,当然也可以使用业界满足 WebSocket 标准规范的开源框架,如 Socket.io。