代码地址: https://github.com/Xavier-777/Instant-Messaging
使用 Sparkjava 作为后端服务器,开发的一个即时聊天室,可以发送文本信息、图片、音频、视频等信息,可以发送 zip、docx等文件,甚至可以进行语音视频通话等功能。
这里的Sparkjava是一个微型web框架,与大数据的spark是完全两个不同的东西。如果你有了解过 Node.js 那么 sparkjava 对你来说很容易上手,因为两者的编写方式很相似,你可以理解为java版的 Node.js ,但是Node.js 是一个异步非阻塞的框架,而sparkjava是同步阻塞的。(实际上是老师要求使用这个框架的!)
这里使用了 agora.io(声网) 的sdk实现,当然你也可以使用其他的sdk
二进制文件用文件上传的方式进行传输,没有走 websocket 的流程
这里使用了声网的sdk实现该功能,具体的参考文档:https://docs.agora.io/cn/Video/landing-page?platform=Web
在我的项目中,需要写自己的 appId 与 appCertificate 才能使用视频通话的功能,建议自己去官网申请一个。更多详情可以去看官方文档
首先了解一下什么是心跳机制。
之所以叫心跳机制是因为:它像心跳一样每隔固定时间向服务器发一次信息,以此来告诉服务器,这个客户端还活着。这个信息没有固定的要求。
那么现在就有两种情况:
1.服务器没有响应,前端无法接收到后端的消息。
2.服务器响应了,但前端没有接收该信息。
针对情况1:最有可能是服务器宕机了,无法响应,websocket断连,释放资源。
情况2:服务器没有宕机,但是该web页面被关闭了,所以接收不到该信息,websocket断连,释放资源。
因此,想要实现心跳检测,服务器必须响应该心跳信息,客户端也要接收该信息
这里给出我的实现方法:
前端:
// 心跳检测包
var heartCheck = {
timeout: 30000, //30秒发一次心跳
timeoutObj: null,
serverTimeoutObj: null,
reset: function(){
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
this.start();
},
start: function(){
var self = this;
this.timeoutObj = setTimeout(function(){
//这里发送一个心跳,后端收到后,返回一个心跳消息,
//onmessage拿到返回的心跳就说明连接正常
ws.send("ping");
self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
ws.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
}, self.timeout)
}, this.timeout)
}
}
webSocket.onopen = function () {
heartCheck.reset(); //心跳检测
};
webSocket.onmessage = function (msg) {
var data = JSON.parse(msg.data);
if (data.heartCheck) {
console.log(data); //获取心跳json
} else {
updateChat(data);//解析json,并更新聊天列表
}
heartCheck.reset(); //心跳检测
};
console.log(data); 打印出心跳检测的信息,以证明客户端还在。
后端:
@OnWebSocketMessage
public void onMessage(Session user, String message) throws IOException {
if (message.equals(heart)) {
broadcastHeartCheck();
} else {
// 广播字符串
broadcastMessage(Main.userUsernameMap.get(user), message);
}
}
broadcastHeartCheck(); 收到的message是heart后,响应相应的心跳信息,以证明服务器还在。
我去了解了一下实现的机制,发现需要用到 redis 缓存数据库,来记录用户的状态。当用户在线时,直接发送信息给该用户;当用户不在线时,将信息存到数据库中,等到用户上线了,再将该信息发给用户,然后将数据库的记录更改为已读状态。更多详细信息见下面的参考资源。
目前还没有去了解,我猜用声网的sdk可以实现,但是我没有认真看完官方文档所以不敢确认。或者用其他的sdk也行。
尚未实现的功能都是超出我目前的能力范围的,希望有dalao可以帮我实现,或者等我能力提升了,再去慢慢实现这些功能。
参考资料:
离线通讯机制:https://zhuanlan.zhihu.com/p/42982409
布隆过滤器:https://zhuanlan.zhihu.com/p/43263751