使用Nodejs实现聊天服务器
两年前在项目中使用nodejs+socket.io+redis实现的聊天和推送服务器,
基本上几百行代码就实现了整个功能,在项目中单服务器单进程可以跑到支持
5000人左右同时在线。
主要思路
- 用户上线后,根据用户的userid和socket,保存到一个全局的map中
- 发送消息时,根据对方的userid找到对应的socket,通过socket.emit发送消息给对方
- 如果对方不在线,在redis中保留消息,在对方上线后推送给用户
- 用户下线后,从全局的map中删除对应的用户socket
- 由于需要保持长连接,客户端需要定时发心跳给服务端,所以定义了一个心跳消息,可以5分钟发一次
-
用户上线
io.sockets.on('connection', function (socket) {
var address = socket.handshake.address;
console.log(Date() + " New connection from " + address.address + ":" + address.port);
socket.on('login', function (userinfo) {
userid = userinfo.myAuraId
var address = socket.handshake.address;
var deviceid = userinfo.deviceId
console.log(Date() + " Login from " + address.address + ":" + address.port + " " + userid + " " + deviceid);
old_socket = sockets[userid]
if (old_socket && old_socket.deviceid && deviceid && old_socket.deviceid != deviceid) {
old_socket.relogin = 1
old_socket.emit('logout')
console.log("logout " + old_socket.userid + " " + old_socket.deviceid)
}
if (old_socket && old_socket != socket) {
old_socket.disconnect()
}
socket.relogin = 0
socket.userid = userid
socket.deviceid = deviceid
//发送离线消息
send_store_msg(socket, userid)
sockets[userid] = socket
//通知业务服务器,用户已登录
pub.publish("login_message_channel", JSON.stringify(userinfo))
}) -
发送消息
socket.on('chat', function (msg, ack) {
//process_msg(msg)
pub.publish("chat_filter_channel", JSON.stringify(msg))
socket.userid = msg.from
sockets[socket.userid] = socket
if (ack) {
ack(1)
}
}) -
接收和回应心跳
socket.on('hb', function (msg, ack) {
if (ack) {
ack(1)
}
}) -
用户下线,删除对应的socket
socket.on("disconnect", function () {
var address = socket.handshake.address;
console.log(Date() + " Disconnect from " + address.address + ":" + address.port);
if (!socket.relogin) {
delete sockets[socket.userid]
}
})
推送服务器
实现了聊天服务器后,对推送来说就很简单了
- 在redis里开个channel,业务服务器往这个channel里publish数据
- nodejs subscribe这个channel监听数据,找到对应用户发送消息即可。
- 用户不在线,可能也需要对这个离线推送消息做保留,具体看业务定义
var notification = redis.createClient()
|
客户端Lib库
服务端是使用socket.io实现,基本上socket.io的Lib都能兼容
以下是推荐的两个客户端Lib:
其他语言版本,可以在github搜索socket.io,找到对应的Lib库
Server端全部代码
//var io = require('socket.io').listen(80) |