Skip to content

Instantly share code, notes, and snippets.

@stableShip
Created March 28, 2016 09:46
Show Gist options
  • Select an option

  • Save stableShip/be355b3b58b70f442dcf to your computer and use it in GitHub Desktop.

Select an option

Save stableShip/be355b3b58b70f442dcf to your computer and use it in GitHub Desktop.
聊天模块连接管理
# 聊天模块通讯管理
----------
## socket现有管理方案
### 连接socket管理
###### `(1. socket.io的封装,目前在/model/socketio/,socket.io服务是承载在默认3001端口(配置在/model/config/index)的http server上,socket事件的监听模式是怎样?)`
在socketio服务端启动时创建了一个`conns: {},` key为用户的uid,value为用户连接socketio的socket对象引用.
当用户连接时将用户uid和socket关联起来.
具体实现:
服务端socket.io服务器启动时,在model/socketio/service/index.js 监听connection事件,并注册`message, disconnect, error`事件监听.
在model/index.js中注册了`C2S_REGISTER_REQ: 注册身份请求`的onMessage处理方法,并监听了`close`事件
当客户端登陆时,发送`C2S_REGISTER_REQ: 注册身份请求`请求给服务端
```
// 客户端发送socketio消息
message_sign.send({
type: MsgType.C2S_REGISTER_REQ,
data:{
type:'user',
uid:data.uid,
deviceid:data.deviceid
}
});
```
()触发服务端`message`事件,监听方法执行:
```
client.on('message', function (str) {
try{
var json;
if(typeof str == 'string'){
json = JSON.parse(str);
}
else {
json = str;
}
o.emit('data', this, json);
o.onMessage(this, json); // 调用message方法,根据type进行通讯分发处理
}catch (e){
o.emit('data', this, str);
}
});
```
调用message方法,根据type进行通讯分发处理
```
// Dispatch a client message
onMessage: function(conn, msg){
console.log("onMessage:",msg);
if(!msg.type || !this.types[msg.type]) return;
if(this.types[msg.type].onMessage){
this.types[msg.type].onMessage(conn, msg);
}
}
```
调用`C2S_REGISTER_REQ: 注册身份请求`类型的onMessage方法,此时会执行:
###### `2. 客户端socket连接的管理是在/model/index中,关键是消息:C2S_REGISTER_REQ的处理逻辑,这里面对socket connection是怎么管理的?请按不同的业务场景描述管理流程;`
```
model.jmsocket.register_type(MsgType.C2S_REGISTER_REQ,{
onMessage:function(conn,msg){
//省略
var curconn = model.jmsocket.conns[conn.uid];
//检测用户是否 异地登陆,通知客户端进行异地登陆处理
if(curconn && conn != curconn){
model.jmsocket.sendTo(conn.uid,{
type: MsgType.S2C_DIFFERENT_CONNECTION,
data: {}
});
}
// 绑定用户uid和socket映射
model.jmsocket.conns[conn.uid] = conn;
//省略
}
```
当用户退出时,请求`/signout`路由,,服务端进行socket处理:
```
// 注销后,服务端删除uid与socket之间的关系
var conn = model.jmsocket.conns[id];
if (conn) {
conn.disconnect(true); // 断开所有连接
delete model.jmsocket.conns[id]; //删除映射关系
}
```
为了保证删除,在model/index.js中监听了socket的close事件,在socket关闭时,删除映射
```
if(onconn && typeof(onconn.id) != 'undefined') {
//省略
delete model.jmsocket.conns[conn.uid];
//省略
}
```
## 通讯协议
定义了19种通讯类型:
```
{ C2S_REGISTER_REQ : 1,
S2C_REGISTER_RES : 2,
S2C_ALONECHAT_PUSH : 3,
S2C_SIGNED_PUSH : 4,
S2C_SYSTEM_PUSH : 5,
S2C_RESERVATION_PUSH : 6,
S2C_DOCTORMSG_PUSH : 7,
S2C_TEAMMATECHAT_PUSH : 8,
S2C_DOCTORFRIENDCHAT_PUSH : 9,
S2C_FRIENDAPPLY_PUSH : 10,
S2C_SOCIAL_PUSH : 11,
S2C_DIFFERENT_CONNECTION : 12,
S2C_REMIND_PUSH : 13,
S2C_UNSIGNED_PUSH : 14,
S2C_TEAMCHAT_PUSH : 15,
S2C_TEAMMEMBER_ENTER : 16,
S2C_TEAMMEMBER_LEAVE : 17,
S2C_VIDEOCALL_INVITE:18,
S2C_VIDEOCALL_END:19
}
```
所有的通讯都通过通讯类型进行区分处理,即使是讨论组聊天,也是遍历所有用户,进行一个个的通讯,
降低了系统复杂度.
因为我们系统不是所有用户实时在线,也只能通过这种形式进行消息广播.不在线用户进行推送通知.同时记录聊天记录.
## http服务器和socketio服务器之间的通讯
在 model/index.js 中创建了一个`o`的内置对象,将该对象传入`createServer`方法,用于保存用户socket连接,在socketio服务器触发message事件时,进行消息处理,可以理解为闭包.
```
module.exports = function(opts) {
if(!opts.port) return;
var o = {
// Client message types
types: {},
// Client connections (bind with: key=uid, value=socket.io.client)
conns: {},
// Register an event (message type) handler
register_type: function(type, opts){
this.types[type] = opts;
},
// Unregister an event (message type) handler
unregister_type: function(type, opts){
delete this.types[type];
},
// Dispatch a client message
onMessage: function(conn, msg){
console.log("onMessage:",msg);
if(!msg.type || !this.types[msg.type]) return;
if(this.types[msg.type].onMessage){
this.types[msg.type].onMessage(conn, msg);
}
}
};
// Use jm-common/event to handle events
jm.enableEvent(o);
// Constructor
createServer(o, opts);
return o;
}
function createServer(o, opts) {
var s = http.createServer(function (req, res) {
res.writeHead(404);
res.end();
}).listen(opts.port);
var io = server.listen(s);
io.on('connection', function(client) {
//model.logger.info('[Socket.io] Connected to a new user %s', client.id);
client.sendJson = function(data){
this.send(JSON.stringify(data));
};
client.on('message', function (str) {
try{
var json;
if(typeof str == 'string'){
json = JSON.parse(str);
}
else {
json = str;
}
o.emit('data', this, json);
o.onMessage(this, json);
}catch (e){
o.emit('data', this, str);
}
});
client.on("disconnect", function (reason) {
o.emit('close', this, reason);
});
client.on("error", function (err) {
o.emit('error', this, err);
});
o.emit('connect', client);
});
return o;
}
```
http服务器中的其他模块要进行socketio的消息发送时,调用`o`对象的`conns`获取相应的socket连接,进行消息发送:
```
model.jmsocket.sendTo = function(uid,json,cb){
cb = cb || function(){};
var conn = model.jmsocket.conns[uid]; //model.jmsocket 为 上述的o对象,根据uid从该对象取出用户socket,进行消息发送
if(conn){
conn.sendJson(json);
cb(true);
}else{
cb(false);
}
};
```
----
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment