WebSocket技术,是用于服务端与浏览器端的基于TCP/IP的会话协议所兴起的一项技术 但凡TCP/IP协议都会经过三次握手,而后进行会话数据的传输。保证数据的可靠性(在网络技术发达的今天,这点已经再也不是问题了) 此项技术放弃了之前的须要定时给服务器发送请求。由服务器刷新数据,而后返回给客户端,这样大大的减小了服务器的负担 咱们如何去实现WebSocketjavascript
我用的环境为 jdk1.7+ Tomcat 7.0.52 服务引用的主要Jar包为 catalina.jar,websocket-api.jar 全来自tomcat/lib下 服务端代码以下:html
package com.zx.websocket; import java.io.IOException; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; /** * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, * 注解的值将被用于监听用户链接的终端访问URL地址,客户端能够经过这个URL来链接到WebSocket服务器端 */ @ServerEndpoint(value="/singlewebsocket") public class WebSocketSingleTest { //静态变量,用来记录当前在线链接数。应该把它设计成线程安全的。 private static Integer onlineCount = 0; //concurrent包的线程安全Map,能够使用Map来存放,其中Key能够为用户标识 private static Map<Session, WebSocketSingleTest> map=new ConcurrentHashMap<Session, WebSocketSingleTest>(); //声明这是用户打开链接处理的方法 @OnOpen public void OnOpen(Session session) throws IOException { System.out.println("有新用户连入!session info is :"+session.getId()); synchronized (onlineCount) { addOnlineCount();//在线用户加1 此方法同步 } map.put(session, this);//添加用户信息 Collection key=map.keySet(); Iterator it=key.iterator(); String ids=""; while(it.hasNext()){ ids+=((Session)it.next()).getId()+","; } session.getBasicRemote().sendText(ids); } //声明这是用户关闭链接处理的方法 @OnClose public void OnClose(Session session) { System.out.println("有用户退出!用户ID is :"+session.getId()); synchronized (onlineCount) { reduiceOnlineCount();//在线用户减1 此方法同步 } map.remove(session);//移除用户信息 } //声明这是异常处理的方法 @OnError public void onError(Session session, Throwable error){ System.out.println("发生错误"); error.printStackTrace(); } //声明这是用户发送消息的方法 @OnMessage public void OnMessage(String message,Session session) { System.out.println("来自客户端的消息:["+message+"]"); /** * 获取消息后,读取message获取传输消息的目标人,根据session的Id能够遍历Map集合 获取Map的对应的Socket类 * 而后在由这个Socket类 发送消息 参见sendMessage * 注:目标人消息应该经过Message从前台传递过来,再由后台遍历处理 */ } public void sendMessage(Session session,String message) throws IOException { session.getBasicRemote().sendText(message); } public static int getOnlineCount() { return onlineCount; } public static void setOnlineCount(int onlineCount) { WebSocketSingleTest.onlineCount = onlineCount; } public synchronized void addOnlineCount() { WebSocketSingleTest.onlineCount++; } public synchronized void reduiceOnlineCount() { WebSocketSingleTest.onlineCount--; } }
Jsp端主要JS代码以下:java
<%@ page language="java" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head> <title>Java后端WebSocket的Tomcat实现</title> </head> <body> Welcome<br/><input id="text" type="text"/> <button onclick="send()">发送消息</button> <hr/> <button onclick="closeWebSocket()">关闭WebSocket链接</button> <hr/> <div id="message"></div> </body> <script type="text/javascript"> var websocket = null; //判断当前浏览器是否支持WebSocket if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:8080/websocket/zxwebsocket"); } else { alert('当前浏览器 Not support websocket') } //链接发生错误的回调方法 websocket.onerror = function () { setMessageInnerHTML("WebSocket链接发生错误"); }; //链接成功创建的回调方法 websocket.onopen = function () { setMessageInnerHTML("WebSocket链接成功"); } //接收到消息的回调方法 websocket.onmessage = function (event) { setMessageInnerHTML(event.data); } //链接关闭的回调方法 websocket.onclose = function () { setMessageInnerHTML("WebSocket链接关闭"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket链接,防止链接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function () { closeWebSocket(); } //将消息显示在网页上 function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; } //关闭WebSocket链接 function closeWebSocket() { websocket.close(); } //发送消息 function send() { var message = document.getElementById('text').value; websocket.send(message); } </script> </html>
这样一个消息推送机制就完成了web
其中发布的时候我碰到的一些问题,在第一次访问的时候, 服务器后台会抱一个错,这个错是一个类型转换异常, DefaultInstanceManager cannot be cast to InstanceManager 百度后知道, 在发布的时候tomcat会将 catalina.jar包加到项目的web-inf下面的lib文件夹下面,这样这个包就会和tomcat下面的lib下面的catalina.jar 包冲突会报java.lang.ClassCastException 解决方案一:在部署的时候 须要在发布后的项目WEB-INF/lib下去掉catalina.jar和websocket-api.jar 解决方案二:修改了tomcat里的context.xml文件,在context 元素下添加<Loader delegate="true" />后端