websocket链接时,若是长时间没有进行数据的通信就会自动断开链接。为了避免让其断开就在要断开的时候自动发送数据进行通信,就产生了心跳链接的效果。javascript
具体的操做就是在客户端创建链接的时候开启发送心跳信息的线程,以后再每次收到信息以后就线程重启。服务端在处理数据的时候多处理一下心跳信息,将其发给链接的用户,从而实现心跳通信。java
服务端代码web
@ServerEndpoint("/video") public class AcgistVideo { //链接超时 public static final long MAX_TIME_OUT = 2 * 60 * 1000; //房间和房间对应的用户列表 public static Map<String, ArrayList<String>> room_user = Collections.synchronizedMap(new HashMap<String, ArrayList<String>>()); //用户的sid和用户的session一一对应 public static Map<String, Session> user_session = Collections.synchronizedMap(new HashMap<String, Session>()); //用户的sid和房间一一对应 public static Map<String, String> userInRoom = Collections.synchronizedMap(new HashMap<String, String>()); public static Logger log = LoggerFactory.getLogger(AcgistVideo.class); /** * 打开websocket * * @param session websocket的session * @param uid 打开用户的UID */ @OnOpen public void onOpen(Session session, @PathParam("uid") String uid) throws IOException { log.info("--------------------onOpen--------------------"); session.setMaxIdleTimeout(MAX_TIME_OUT); } /** * 收到消息 * * @param message 消息内容 * @param session 发送消息的session */ @OnMessage public void onMessage(String message, Session session) { log.info("接收到来自客户端--" + session.getId() + "--的信息:" + message); JSONObject json = JSONObject.fromObject(message); if (json.get("type").equals("create")) { ArrayList arrayList = new ArrayList(); arrayList.add(session.getId()); String roomId = createRoom(); room_user.put(roomId, arrayList); userInRoom.put(session.getId(), roomId); user_session.put(session.getId(), session); JSONObject jsonstr = new JSONObject(); jsonstr.put("type", "create"); jsonstr.put("room", roomId); jsonstr.put("sid", session.getId()); jsonstr.put("count", getUserNumberByRoom(roomId)); sendMessage(jsonstr.toString(), session); } else if (json.get("type").equals("apply")) { String roomId = ""; if (json.has("room")) { roomId = json.getString("room"); } if (!("".equals(roomId)) && null != room_user.get(roomId)) { ArrayList<String> arrayList = room_user.get(roomId); arrayList.add(session.getId()); room_user.put(roomId, arrayList); userInRoom.put(session.getId(), roomId); user_session.put(session.getId(), session); JSONObject jsonstr = new JSONObject(); jsonstr.put("type", "apply"); jsonstr.put("room", roomId); jsonstr.put("sid", session.getId()); jsonstr.put("count", getUserNumberByRoom(roomId)); sendMessageToUserInSameRoom(session.getId(), jsonstr, false); } else { ArrayList arrayList = new ArrayList(); arrayList.add(session.getId()); roomId = createRoom(); room_user.put(roomId, arrayList); userInRoom.put(session.getId(), roomId); user_session.put(session.getId(), session); JSONObject jsonstr = new JSONObject(); jsonstr.put("type", "create"); jsonstr.put("room", roomId); jsonstr.put("sid", session.getId()); jsonstr.put("count", getUserNumberByRoom(roomId)); sendMessage(jsonstr.toString(), session); } } else if (json.get("type").equals("receipt")) { Session oession = user_session.get(json.get("sid")); JSONObject jsonstr = new JSONObject(); jsonstr.put("type", "receipt"); jsonstr.put("room", json.get("room")); jsonstr.put("sid", session.getId()); jsonstr.put("count", getUserNumberByRoom(userInRoom.get(session.getId()))); sendMessage(jsonstr.toString(), oession); } else if (json.get("type").equals("link")) { Session oession = user_session.get(json.get("sid")); JSONObject jsonstr = new JSONObject(); jsonstr.put("type", "link"); jsonstr.put("room", json.get("room")); jsonstr.put("sid", session.getId()); jsonstr.put("count", getUserNumberByRoom(userInRoom.get(session.getId()))); sendMessage(jsonstr.toString(), oession); } else if (json.get("type").equals("offer")) { Session oession = user_session.get(json.get("sid")); JSONObject jsonstr = new JSONObject(); jsonstr.put("type", "offer"); jsonstr.put("room", json.get("room")); jsonstr.put("sid", session.getId()); jsonstr.put("count", getUserNumberByRoom(userInRoom.get(session.getId()))); jsonstr.put("offer", json.get("offer")); sendMessage(jsonstr.toString(), oession); } else if (json.get("type").equals("answer")) { Session oession = user_session.get(json.get("sid")); JSONObject jsonstr = new JSONObject(); jsonstr.put("type", "answer"); jsonstr.put("room", json.get("room")); jsonstr.put("sid", session.getId()); jsonstr.put("count", getUserNumberByRoom(userInRoom.get(session.getId()))); jsonstr.put("answer", json.get("answer")); sendMessage(jsonstr.toString(), oession); } else if (json.get("type").equals("candidate")) { Session oession = user_session.get(json.get("sid")); JSONObject jsonstr = new JSONObject(); jsonstr.put("type", "candidate"); jsonstr.put("room", json.get("room")); jsonstr.put("sid", session.getId()); jsonstr.put("count", getUserNumberByRoom(userInRoom.get(session.getId()))); jsonstr.put("candidate", json.get("candidate")); sendMessage(jsonstr.toString(), oession); } else if (json.get("type").equals("bye")) { remove(session); } else if (json.get("type").equals("beat")) { JSONObject jsonstr = new JSONObject(); jsonstr.put("type", "beat"); jsonstr.put("msg", json.get("msg")); jsonstr.put("sid", session.getId()); sendMessageToUserInSameRoom(session.getId(), jsonstr, false); } } /** * websocket错误 * * @param e * @param session */ @OnError public void onError(Throwable e, Session session) { log.info("--------------------onError--------------------"); log.info("session ID: --" + session.getId() + " --离开了"); log.error("--", e); log.info("----------------------------------------"); } /** * websocket关闭 * * @param session 关闭的session */ @OnClose public void onClose(Session session) { log.info("--------------------onClose--------------------"); remove(session); } /** * * 随机生成UUID * * @return * */ public static synchronized String getUUID() { log.info("--------------------getUUID--------------------"); UUID uuid = UUID.randomUUID(); String str = uuid.toString(); String uuidStr = str.replace("-", ""); return uuidStr; } /** * 经过房间号获取房间中的用户数量 * * @param roomId 房间号 * @return 房间中的用户数量 若是只为-1则房间不存在 */ public int getUserNumberByRoom(String roomId) { log.info("--------------------getUserNumberByRoom--------------------"); if (room_user.containsKey("roomId")) { ArrayList<String> userList = room_user.get(roomId); return userList.size(); } else { return -1; } } /** * 发送信息 * * @param message 发送内容 * @param session 用户session */ public void sendMessage(String message, Session session) { log.info("--------------------sendMessage--------------------"); try { log.info("发送消息到客户端--" + session.getId() + "--信息为:" + message); synchronized (session) { if (session.isOpen()) { session.getBasicRemote().sendText(message); } } } catch (Exception e) { log.error("send message exception", e); } } /** * 建立房间 * * @return 房间ID */ public String createRoom() { log.info("--------------------createRoom--------------------"); String roomId = getUUID(); return roomId; } /** * 移除聊天用户 * * @param session 移除的session */ private void remove(Session session) { log.info("--------------------remove--------------------"); String roomId = userInRoom.get(session.getId()); ArrayList<String> arrayList = room_user.get(roomId); if (arrayList.contains(session.getId())) { log.info("移除SID:" + session.getId()); arrayList.remove(session.getId()); if (arrayList.size() < 1) { log.info("移除房间:" + roomId); room_user.remove(roomId); } else { room_user.put(roomId, arrayList); //用户退出的时候给房间中的每一位用户发一条信息 JSONObject jsonstr = new JSONObject(); jsonstr.put("type", "bye"); jsonstr.put("sid", session.getId()); sendMessageToUserInSameRoom(session.getId(), jsonstr, false); } userInRoom.remove(session.getId()); user_session.remove(session.getId()); } } /** * 给用户所在房间中的每一位用户发一条信息 * * @param selfId 用户Id * @param jsonstr 须要发的信息 * @param isSendSelf 是否发给本身 */ private void sendMessageToUserInSameRoom(String selfId, JSONObject jsonstr, boolean isSendSelf) { String roomId = userInRoom.get(selfId); ArrayList<String> arrayList = room_user.get(roomId); for (int i = 0; i < arrayList.size(); i++) { if (arrayList.get(i).equals(selfId)) { if (isSendSelf) { sendMessage(jsonstr.toString(), user_session.get(arrayList.get(i))); } } else { sendMessage(jsonstr.toString(), user_session.get(arrayList.get(i))); } } } }客户端代码
var MyWebSocket = function (obj) { var _this = this; this.timeout = 30 * 1000; this.timeoutObj = null; this.socket = null; this.initSocket = function () { this.socket = new WebSocket(GLOBAL.getConstant("WEB_SOCKET_URL")); this.socket.onopen = function () { console.log("websocket-----> Opened"); _this.start(); }; this.socket.onmessage = this.socketMessage; this.socket.onclose = function () { console.log("websocket-----> Closed"); obj.closeWebSocket(); }; this.socket.onerror = function () { console.log("websocket-----> Error:" + JSON.stringify(event)); }; console.log("-------websocket初始化完成执行回调函数-------"); obj.initWebRtc(obj.entitys); } //接收到服务器的回复 this.socketMessage = function (message) { console.log("websocket-----> Message:" + message.data); _this.reset(); obj.SocketCallBack(message.data); } //向服务器发送信息 this.sendMessage = function (message, callback) { this.waitForConnection(function () { var msgJson = JSON.stringify(message); this.socket.send(msgJson); console.log("websocket-----> SendMessage:" + msgJson); if (typeof callback !== 'undefined') { callback(); } }, 1000); }; this.waitForConnection = function (callback, interval) { if (this.socket.readyState === 1) { callback(); } else { var that = this; setTimeout(function () { that.waitForConnection(callback, interval); }, interval); } }; this.onClose = function () { this.socket.close(); } this.start = function () { _this.timeoutObj = setTimeout(function () { var heartbeat = { type: "beat", msg: "HeartBeat" }; _this.socket.send(JSON.stringify(heartbeat)); }, _this.timeout) }; this.reset = function () { clearTimeout(this.timeoutObj); _this.start(); }; this.initSocket(); return this; }