原文链接:https://blog.csdn.net/jiangyou4/article/details/53586305
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;
}