使用Websocket和Servlet实现服务器定点推送

2016-05-30 10:48钱宇虹
软件工程 2016年10期

钱宇虹

摘 要:针对Java Web实时系统中的消息推送这一关键问题,本文基于Tomcat8和WebSocket标准,提出并且实现了一个服务端定点推送模型,能够向指定的Web注册用户进行消息推送。该模型具有非广播的特点,即在没有浏览器请求的情况下通过Servlet主动将消息推送至某个已注册的Web用户。该模型已经成功地应用于呼叫中心系统中将电话分机状态和弹屏信息推送给Web坐席,该模型也可以用于即时消息、游戏应用、实时证券报价、股票系统等Web实时系统,具有广泛的使用价值。

关键词:Tomcat8;WebSocket;定点推送

中图分类号:TP311 文献标识码:A

1 引言(Introduction)

众所周知,HTTP协议是基于请求-响应模式的无状态的单向协议,即每次都要由客户端(如浏览器)主动向服务端发出“请求”,服务端做出处理后将结果作为“响应”返回给客户端。“无状态”指的是每次的请求-响应都必须经历建立连接和释放连接的过程,前一次连接和后一次连接相互之间没有关系。“单向”指的是客户端是主动方,服务端是被动方,服务端不能主动向客户端发送数据。HTTP协议的这一特点对传统的Web应用,像电子商务网站、搜索引擎等等非常合适,但是不能满足日益增强的实时性需求的Web应用,这些应用要求在无需客户端发出请求的前提下,服务端能实时地将信息主动推送到客户端,如基于Web的聊天系统、即时消息、游戏应用、实时证券报价和股票系统等。

过去,针对实时性较强的应用,开发人员使用轮询和Comet技术这些折中方案。轮询就是客户端按照预先设置的时间间隔向服务端发送请求,周期性地查询是否有数据更新。早期的轮询是通过在HTML头部插入META元信息来实现网页的自动刷新,后来人们使用AJAX轮询。AJAX轮询带来的最大好处就是在不刷新整个页面的前提下可以实现网页的局部更新,既提高了做事的效率又增强了用户体验,但是AJAX还是受限于请求-响应模式,由于无法预期什么时候推送消息,造成很多无效的请求。而Comet是使用一种新的技术去做轮询得到的效果,这种技术虽然可以实现双向通信,但是依然需要发出请求,而且Comet普遍采用长连接,这会导致大量消耗服务器带宽和资源。Comet技术本质上还是没有摆脱HTTP请求-响应模式,不能算是真正意义上的双向通信,并且开发复杂度也较高。

随着HTML5推出WebSocket,为真正解决服务器推送提供了技术保障。该规范旨在浏览器中实现和服务器端的双向通信,用以拓展浏览器上的应用类型,如实时监控系统[1]、校园通知系统[2]。WebSocket规范实际上由两部分组成,一部分是浏览器中的WebSocket API,由W3C制订;一部分是WebSocket协议,由IETF制订。它引入WebSocket接口,在WEB上通过一个单一的套接字(Socket)定义了一个全双工的通信通道,与通过维持两个连接来模拟全双工通信的轮询和长轮询方案相比,WebSocket大幅降低了不必要的网络流量和延迟[3]。WebSocket是为解决WEB客户端与服务端实时通信而产生的技术,协议设计的一个重要原则就是能和现有的Web方式和睦共处,其本质是首先通过HTTP/HTTPS协议进行握手后创建一个用于交换数据的TCP连接,此后WEB客户端与服务端就此TCP连接进行实时通信[4]。

2 Tomcat8对WebSocket的支持(Tomcat8 support

for WebSocket)

WebSocket在浏览器端的实现遵循标准的HTML5,这个和服务器采用Tomcat或者Jetty是无关的,标准化的形式是WebSocket JavaScript API[5],主流的浏览器上都得到很好的支持,所以通过JavaScript书写Web客户端的代码既标准也较为简单。值得大家注意的是服务器端的实现在形成统一标准之前,各个实现都有自己的一套API,所以使用WebSocket开发服务器端存在一定的风险。

Tomcat7.0.27是Tomcat支持WebSocket的第一个版本,其关键是提供了org.apache.catalina.websocket.WebSocketServlet接口,在Tomcat7.0.27中需要一个Servlet来处理WebSocket请求,这个Servlet要继承自WebSocketServlet这个类,然后实现createWebSocketInbound方法,该方法返回StreamInbound对象。这个接口是非标准的WebSocket实现,到Tomcat8中,WebSocketServlet和StreamInbound这两个类都过期了,所以基于Tomcat7.0.27来实现服务器推送的技术在这里不再赘述[6]。

在Java社区技术的进步常常经历这样的阶段,就是不同的供应商和开发人员编写类库实现某种技术,随着时间的推移当该技术成熟时它就被标准化,使得开发者能够在不同的实现之间相互操作,避免冒锁定特定供应商的风险。JSR356就是把WebSocket的Java API进行标准化的结果,它已经成为JavaEE 7标准的一部分,这意味着所有JavaEE 7兼容的应用服务器都遵守JSR356的WebSocket协议标准。

Tomcat8是真正支持JSR356标准的,它自带的WebSocket API包是在Tomcat8安装目录下的lib目录中的websocket-api.jar[7],我们需要此jar包设置到项目的classpath中。在Tomcat8中使用WebSocket的代码如下:

(1)Web客户端(JavaScript代码,与服务器类型无关)

...……
icp