websocket+心跳实现长连接

1.js部分

var lockReconnect = false;  //避免ws重复连接
		var ws = null;          // 判断当前浏览器是否支持WebSocket
		var wsUrl = "ws:"+ip+":8081";

		createWebSocket(wsUrl);   //连接ws
		
		function createWebSocket(url) {
		    try {
		        if ('WebSocket' in window) {
		            ws = new WebSocket(url);
		        } else if ('MozWebSocket' in window) {
		            ws = new MozWebSocket(url);
		        } else {
		            layui.use(['layer'], function () {
		                var layer = layui.layer;
		                layer.alert("您的浏览器不支持websocket协议,建议使用新版谷歌、火狐等浏览器,请勿使用IE10以下浏览器,360浏览器请使用极速模式,不要使用兼容模式!");
		            });
		        }
		        initEventHandle();
		    } catch (e) {
		        reconnect(url);
		        console.log(e);
		    }
		}
function initEventHandle() {
		    ws.onclose = function () {
		        console.log("llws连接关闭!" + new Date().toUTCString());
		        var start=0;
		        reconnect(wsUrl);
		    };
		    ws.onerror = function () {
		        console.log("llws连接错误!");
		        reconnect(wsUrl);
		    };
		    ws.onopen = function () {
		    	ws.send(uid);
		        heartCheck.reset().start();      //心跳检测重置
		        console.log("llws连接成功!" + new Date().toUTCString());
		    };
		    ws.onmessage = function (event) {    //如果获取到消息,心跳检测重置
		        var eventData = event.data;
		        handMsg(eventData);
		        heartCheck.reset().start();      //拿到任何消息都说明当前连接是正常的
		    };
		}
		
		// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
		window.onbeforeunload = function () {
		    ws.close();
		}
		
		function reconnect(url) {
		    if (lockReconnect) return;
		    lockReconnect = true;
		    setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
		        createWebSocket(url);
		        lockReconnect = false;
		    }, 5000);
		}
		
		//心跳检测
		var heartCheck = {
		    timeout: 60000,        //1分钟发一次心跳
		    timeoutObj: null,
		    serverTimeoutObj: null,
		    reset: function () {
		        clearTimeout(this.timeoutObj);
		        clearTimeout(this.serverTimeoutObj);
		        return this;
		    },
		    start: function () {
		        var self = this;
		        this.timeoutObj = setTimeout(function () {
		            ws.send(uid);
		            self.serverTimeoutObj = setTimeout(function () {
		                ws.close();     
		            },self.timeout)
		        },this.timeout)
		    }
		}
function handMsg(eventData){
	//ajax连接后台处理业务...
}

2.后台代码

//使用监听器机制实现ServletContextListener接口
public class WebContextListener implements ServletContextListener{
	
	//消亡时执行的方法
	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		
	}
	//项目启动时初始化执行的方法
	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		 WebSocketImpl.DEBUG = false;
	        int port = 8081;
	        WsServer wsServer = new WsServer(port);
	        wsServer.start();

	        /*new Thread(new Runnable() {
	            @Override
	            public void run() {
	                while (true) {
	                    try {
	                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
	                        String msg = simpleDateFormat.format(new Date());
	                        System.out.println(msg);
	                        Collection<String> allOnlineUser = WsPool.getAllOnlineUser();
	                        System.out.println(allOnlineUser.size());
	                        if (allOnlineUser.size() > 0) {
	                            WsPool.sendMessageToAll(msg);
	                        }

	                        Thread.sleep(5000);
	                    } catch (InterruptedException e) {
	                        e.printStackTrace();
	                    }
	                }
	            }
	        }).start();*/
		
	}

}
//连接池
public class WsPool {
	private static final Map<WebSocket, String> wsUserMap = new HashMap<WebSocket, String>();
	//单发
	public static WebSocket test(String name){
        Set<WebSocket> keySet = wsUserMap.keySet();
		for(WebSocket socket : keySet){
			String string = wsUserMap.get(socket);
			if(name.equals(string)){
				return socket;
			}
		}
		return null;
	}
	//群发
	public static List<WebSocket> massTexting(String name){
		List<WebSocket> fbList = new ArrayList<WebSocket>();
			Set<WebSocket> keySet = wsUserMap.keySet();
			for(WebSocket socket : keySet){
				String string = wsUserMap.get(socket);
				if(name.equals(string)){
					fbList.add(socket);
				}
			}
		return fbList;
	}
    /**
     * 通过webSocket连接获取用户
     * @param conn
     * @return
     */
    public static String getUserByWs(WebSocket conn) {
        return wsUserMap.get(conn);
    }

    /**
     * 根据用户获取webSocket对象
     * 此处应返回的是一个websocket集合,但是在close方法中将失效的连接移除,
     * 所以保证返回的是一个
     * @param userName
     * @return
     */
    public static WebSocket getWsByUser(String userName) {
        Set<WebSocket> webSockets = wsUserMap.keySet();
        synchronized (webSockets){
            for (WebSocket conn : webSockets) {
                if (conn.equals(userName)) {
                    return conn;
                }
            }
        }
        return null;
    }

    /**
     * 获取所有的在线用户
     * @return
     */
    public static Collection<String> getAllOnlineUser() {
        List<String> users = new ArrayList<String>();
        Collection<String> values = wsUserMap.values();
        for (String value : values) {
            users.add(value);
        }
        return users;
    }

    /**
     * 向连接池中添加连接
     * @param userName
     * @param conn
     */
    public static void addUser(String userName, WebSocket conn) {
        wsUserMap.put(conn, userName);
    }

    /**
     * 移除池中的特定连接
     * @param conn
     * @return
     */
    public static boolean removeUser(WebSocket conn) {
        if (wsUserMap.containsKey(conn)) {
            wsUserMap.remove(conn);
            return true;
        }else {
            return false;
        }
    }

    /**
     * 向一特定的用户发送消息
     * @param msg
     * @param conn
     */
    public static void sendMessageToUser(String msg, WebSocket conn) {
        if (null != conn && null != wsUserMap.get(conn)) {
            conn.send(msg);
        }
    }

    /**
     * 向所用的用户发送消息
     * @param msg
     */
    public static void sendMessageToAll(String msg) {
        Set<WebSocket> webSockets = wsUserMap.keySet();
        synchronized (webSockets) {
            for (WebSocket conn : webSockets) {
                String user = wsUserMap.get(conn);
                if (null != user) {
                    conn.send(msg);
                }
            }
        }
    }
}
public class WsServer extends WebSocketServer{

    public WsServer(int port) {
        super(new InetSocketAddress(port));
    }

    public WsServer(InetSocketAddress address) {
        super(address);
    }

    /**
     * 连接时触发
     */
    @Override
    public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {
        //LOGGER.debug("connected~~~~~~");
        System.out.println("connected~~~~~~");
    }

    /**
     * 断开连接时触发的方法
     */
    @Override
    public void onClose(WebSocket webSocket, int code, String reason, boolean remote) {
        //断开连接时,移除连接
        userLeave(webSocket);
        System.out.println(reason);
    }

    @Override
    public void onMessage(WebSocket webSocket, String msg) {
        	System.out.println(msg);//获取用户名
            userJoin(webSocket, msg);
            webSocket.send(msg);
    }

    /**
     * 错误时触发
     */
    @Override
    public void onError(WebSocket webSocket, Exception e) {
        System.out.println("on error");
        e.printStackTrace();
    }

    /**
     * 将连接从池中移除
     * @param conn
     */
    private void userLeave(WebSocket conn) {
        WsPool.removeUser(conn);
    }

    /**
     * 向池中添加连接
     * @param conn
     * @param userName
     */
    private void userJoin(WebSocket conn, String userName) {
        WsPool.addUser(userName, conn);
    }
}
//在service层处理完业务逻辑之后在控制层调用连接池的方法
WebSocket webSocket = WsPool.test(us.getuId());
		if(webSocket!=null){
			webSocket.send(us.getuId());
		}

本人已测可用!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值