- 常见的WEB端消息推送方案及其优劣
1.轮询(Polling)
常见的轮询方式就是使用AJAX 定时(可以使用JS的 setTimeout 函数)去服务器查询是否有新消息,从而进行增量式的更新。这种方式间隔多长时间再查询是个问题,因为性能和即时性是反比关系。间隔太短,海量的请求会拖垮服务器,间隔太长,服务器上的新数据就需要更长的时间才能到达客户端;
- 优点:使用方便,服务端逻辑编写简单;
- 缺点:轮询方式下不能做到完全的实时性且大量请求下服务器压力大,无效请求多,实际生产环境使用少,效率差,浪费带宽和服务器资源;
2.长轮询(Long-Polling)
长轮询就是在轮询的基础上添加响应机制,客户端向服务器发送AJAX请求,服务器接收到请求后保持连接,直到有新消息或超时(设置)才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求;此种方式在网页版的微信中可见,其用两个请求来完成长轮询,一个用于25秒超时获取是否有新消息,当有新消息时会用另一个AJAX请求来获取具体数据,有较高的可用性;
- 优点:兼容所有浏览器,有消息响应机制,实时性好,按需请求服务器,减少无效请求;
- 缺点:长轮询方式下长时间保持与服务器连接比较消耗资源,而且连接的创建与销毁比较繁琐,浪费资源,而且返回数据顺序无保证,难于管理维护;
3.基于iframe方式的长连接
通过在 HTML 页面里嵌入一个隐蔵帧,然后将这个隐蔵帧的 src 属性设为对一个长连接的请求,服务器端并不返回直接显示在页面的数据,而是返回对客户端 Javascript 函数的调用,并将返回的数据作为客户端 JavaScript 函数的参数传递;客户端浏览器的 Javascript 引擎在收到服务器返回的 JavaScript 调用时就会去执行代码。
- 优点:每次数据传送不会关闭连接,连接只会在通信出现错误时,或是连接重建时关闭,实时性好,不发无用请求,管理相对方便;
- 缺点:服务器维护一个长连接会增加开销,而且IE、Morzilla Firefox 下端的进度栏都会显示加载没有完成,在交互和兼容性上有待提升;
4.基于插件的socket方式
常见的有Flash XMLSocket、Java Applet套接口、Activex包装的socket;比如Flash XMLSocket是在HTML页面中嵌入一个使用了XMLSocket类的Falsh程序。JavaScript通过调用此Flash程序提供的套接口接口与服务端的套接口进行通信。JavaScript在收到服务器端以XML格式传送的信息控制HTML的Dom对象改变页面的内容显示。
- 优点:原生socket的支持,PC端和移动端的实现方式相似,实现真正的即时通信,而不是伪即时;
- 缺点:客户端需安装相应的插件;
5. WebSocket
WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信;
- 优点:建立在 TCP 协议之上,没有同源限制,客户端可以与任意服务器通信,服务器端的实现比较容易;使用ws或者wss协议的客户端socket,可以使用wss协议加密,安全性好;全双工双向通信,能够真正意义上实现即时消息处理,使用Web套接字操作,消除了开销,并大大降低了复杂性;
- 缺点:少部分浏览器不支持,浏览器支持的程度与方式有区别(可参考官网);
- WebSocket介绍及其使用案例
- 基于JavaEE的 WebSocket 使用介绍
JavaEE7 的JSR-356:Java API for WebSocket,已经对WebSocket做了支持。不少Web容器,如Tomcat、Jetty等都支持WebSocket。Tomcat从7.0.27开始支持WebSocket,从7.0.47开始支持JSR-356;
1.WebSocket客户端
WebSocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信。在WebSocket中有两个方法:
- SEND() 向远程服务器发送数据。
- CLOSE() 关闭WebSocket链接。
WebSocket同时还定义了几个监听函数:
- ONOPEN() 当网络连接建立时触发。
- ONERROR() 当网络发生错误时触发。
- ONCLOSE() 当WebSocket被关闭时触发。
- ONMESSAGE() 当WebSocket接收到服务器发来的消息的时触发。
WebSocket的readyState属性返回实例对象的当前状态,共有四种:
- CONNECTING:值为0,表示正在连接。
- OPEN:值为1,表示连接成功,可以通信了。
- CLOSING:值为2,表示连接正在关闭。
- CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
2.WebSocket服务端
JSR356定义了WebSocket的规范,Tomcat7中实现了该标准。JSR356 的 WebSocket 规范使用 javax.websocket.*的 API,可以将一个普通 Java 对象(POJO)使用 @ServerEndpoint 注释作为 WebSocket 服务器的端点。使用@ServerEndpoint注释的无参构造函数建立了一个WebSocket的服务端:
//将WebSocket服务端运行在ws://[Server端IP或域名]:[Server端口]/项目/test的访问端点
@ServerEndpoint("/test")
public class TestEndpoint {
/**
* @Description:连接打开时执行
* @param session 连接建立的会话
*/
@OnOpen
public void onOpen(Session session) throws IOException {
...
}
/**
* @Description:收到消息时执行,接收传入的WebSocket信息,这个信息可以是文本格式,也可以是二进制格式
* @param message 消息体
*/
@OnMessage
public String onMessage(String message) {
...
}
/**
* @Description:连接错误时执行
* @param t 异常信息
*/
@OnError
public void onError(Throwable t) {
...
}
/**
* @Description:连接关闭时执行
* @param session 会话
* @param reason 关闭原因
*/
@OnClose
public void onClose(Session session, CloseReason reason) {
...
}
}
总的来说,socket在应用程序间通信被广泛使用,如果需要兼容低版本的浏览器,建议使用反向ajax或长链接实现;如果纯移动端或不需考虑非现代浏览器则可以直接使用WebSocket。Flash实现推送消息的方法不建议使用,因为依赖插件且手机端支持不好。关于反向ajax也有一些封装好的插件如Pushlet等,按需使用相应的消息推送方案即可。推荐参考的网站如下:
https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket
https://blog.youkuaiyun.com/linlzk/article/details/50153745 (低版本浏览器使用socketJs处理方案)
https://blog.youkuaiyun.com/PacosonSWJTU/article/details/51914567