整条知识链已建立好,剩下就是慢慢把整体描画完整,一边补充知识点了; 课题是建立一个自己的框架,暂定目标是基于WebSocket的Web2.0 SPA,Ajax只会作为补充,自己玩就不考虑用户了; 今天把WebSocket-Node改造了一下,让它认得哪个用户发送信息,回复的时候只回复给源头; 我用了一个Child_process处理数据库的工作,尽量折腾一点,也可以合理分布资源; 接下来先简单说一下WebSocket-Node的设计思路:
1,建立wsServer实例时,在http服务器挂上’upgrade’事件,每一个用户连接进来upgrade的时候,调用handleUpgrade方法 2,handleUpgrade方法会建立wsRequest实例,然后调用实例的handShake()方法,通过后emit在App.js写的’request’事件 3,触发request事件后,调用wsRequest.accept()构造函数,过程建立新的wsConnection对象并返回之,返回前触发’requestAccepted’事件 4,’requestAccepted’事件会把新建立的wsConnection对象传入wsServer的connections数组!
所以,有多少个用户连接进来,wsServer的connections数组就有多少个元素,用户连接断开后删除对应的数组元素;
改造思路: 因为是child_process处理数据库,简单的只在其’message’事件挂上connection.sendUTF并不合理,因为一个message会触发所有用户的’message’事件,结果就是每一个用户都接收到相同的信息;如果想用数组操作每一个wsConnection实例,就要用indexOF遍历,因为每一次用户进出,都会改变其他用户的实例的位置:
WebSocketServer.prototype.handleRequestAccepted = function(connection) {
var self = this;
connection.once('close', function(closeReason, description) {
self.handleConnectionClose(connection, closeReason, description);
});
this.connections.push(connection);
this.emit('connect', connection);
};
WebSocketServer.prototype.handleConnectionClose = function(connection, closeReason, description) {
var index = this.connections.indexOf(connection);
if (index !== -1) {
this.connections.splice(index, 1);
}
this.emit('close', connection, closeReason, description);
我暂时的想法是用对象代替数组,因为cookie那边还没想好和浏览器的约定,我先用随机数做用户的session,用connections[random]来储存用户session
WebSocketServer.prototype.handleRequestAccepted = function(connection) {
var self = this;
var randomName=Math.floor(Math.random() * 1000000);
var checkClientNumber = function(){
if(self.connections[randomName]){
randomName = Math.floor(Math.random() * 1000000);
checkClientNumber();
}
return;
}
checkClientNumber();
connection.once('close', function(closeReason, description) {
self.handleConnectionClose(connection, closeReason, description);
});
connection.clientNumber=randomName;
this.connections[randomName]=connection;
this.emit('connect', connection);
};
WebSocketServer.prototype.handleConnectionClose = function(connection, closeReason, description) {
delete this.connections[connection.clientNumber];
this.emit('close', connection, closeReason, description);
};
这样改造好,每一个wsConnection实例都会有自己的clientNumber,在用户连接成功后直接发送给用户,浏览器端保存进ws对象; 而和child_process交流的时候,都用一个对象交流,对象其中一个属性为clientNumber,并和child返回的对象一并发回; 把wsServer的’request’事件多传入一个this参数,让callback能访问这个实例,最后就可以调用每一个对应用户的wsConnection实例了:
wsServer.on('request', function(wsRequest,wsServer){
var connection = wsRequest.accept('big-protocol', wsRequest.origin);
console.log((new Date()) + ' Connection accepted.');
connection.sendUTF(connection.clientNumber);
dbChild.on('message', function(msg){
wsServer.connections[msg.cNum].sendUTF(msg.msg);
});
//.................etc
除了说思路,还想请教一下,这样操作一个巨大的对象如wsServer.connections[msg.cNum]会不会造成性能问题? 我的想法是总比操作数组好吧?
上面的’request’事件写错了
上面这样写会导致每一个用户进来都声明一次’message’事件,有一亿个用户进来,就会回复一亿次重复的信息…低级错误了…
dbChlid.on应该在wsServer.on外面
var wsServer = new WebSocketServer({
httpServer: server,
autoAcceptConnections: false
});
dbChild.on('message', function(msg){
wsServer.connections[msg.cNum].sendUTF(msg.msg);
});
wsServer.on('request', function(wsRequest, wsServer){
//....etc