websocket連接時,如果長時間沒有進行數據的通訊就會自動斷開連接。爲了不讓其斷開就在要斷開的時候自動發送數據進行通訊,就產生了心跳連接的效果。
具體的操作就是在客戶端建立連接的時候開啓發送心跳信息的線程,之後再每次收到信息之後就線程重啓。服務端在處理數據的時候多處理一下心跳信息,將其發給連接的用戶,從而實現心跳通訊。
服務端代碼
@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;
}