关于WebSocket-Node模块的Session改造[Nodejs版 更新0.2]
关于WebSocket-Node模块的Session改造[Nodejs版 更新0.2]
整条知识链已建立好,剩下就是慢慢把整体描画完整,一边补充知识点了; 课题是建立一个自己的框架,暂定目标是基于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
关于WebSocket-Node模块的Session改造[Nodejs版 更新0.2]
整条知识链已建立好,剩下就是慢慢把整体描画完整,一边补充知识点了。课题是建立一个自己的框架,暂定目标是基于WebSocket的Web2.0 SPA,Ajax只会作为补充,自己玩就不考虑用户了。
今天把WebSocket-Node改造了一下,让它认得哪个用户发送信息,回复的时候只回复给源头。我用了一个child_process
处理数据库的工作,尽量折腾一点,也可以合理分布资源。
WebSocket-Node的设计思路
-
建立wsServer实例:
- 在HTTP服务器挂上
'upgrade'
事件,每个用户连接进来时调用handleUpgrade
方法。
- 在HTTP服务器挂上
-
handleUpgrade方法:
- 建立
wsRequest
实例,然后调用实例的handShake()
方法,通过后触发在App.js
中定义的'request'
事件。
- 建立
-
触发
request
事件:- 调用
wsRequest.accept()
构造函数,过程中建立新的wsConnection
对象并返回之。返回前触发'requestAccepted'
事件。
- 调用
-
'requestAccepted'
事件:- 把新建立的
wsConnection
对象传入wsServer
的connections
数组。
- 把新建立的
// 示例代码
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);
};
改造思路
由于使用child_process
处理数据库,简单的在'message'
事件上挂上connection.sendUTF
并不合理,因为一个消息会触发所有用户的'message'
事件,导致每个用户都接收到相同的信息。如果想用数组操作每一个wsConnection
实例,需要遍历数组,因为每次用户进出都会改变其他用户的实例位置。
为了改进这一点,可以使用对象代替数组。通过随机数生成用户的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);
};
优化后的代码
确保dbChild.on('message')
事件只声明一次,避免重复事件触发:
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) {
var connection = wsRequest.accept('big-protocol', wsRequest.origin);
console.log((new Date()) + ' Connection accepted.');
connection.sendUTF(connection.clientNumber);
// 其他逻辑...
});
性能考量
使用对象来存储连接可能会减少数组操作带来的性能问题。但是,对于非常大的连接数量,仍然需要注意内存和性能。建议根据实际情况进行测试和优化。
为什么websocket-node到现在还没有加入session,这样我就没办法处理单聊啊,求指导
在这个帖子中,作者讨论了如何使用 WebSocket-Node
模块改造 session 管理,以便能够区分不同用户并仅向源用户发送消息。作者提出了一种通过使用对象而非数组来存储连接的方法,从而更高效地管理和查找特定的连接。
改造思路
-
使用对象存储连接:
- 每个连接分配一个随机的
clientNumber
。 - 使用该
clientNumber
作为键,将连接存储在connections
对象中。
- 每个连接分配一个随机的
-
处理连接和关闭:
- 在连接成功时,生成一个唯一的
clientNumber
并将其分配给连接对象。 - 将连接添加到
connections
对象中。 - 当连接关闭时,从
connections
对象中删除相应的连接。
- 在连接成功时,生成一个唯一的
示例代码
const WebSocketServer = require('websocket').server;
const http = require('http');
const server = http.createServer();
server.listen(8080);
const wsServer = new WebSocketServer({ httpServer: server });
let connections = {};
wsServer.on('request', function(request) {
const connection = request.accept('my-protocol', request.origin);
const clientNumber = Math.floor(Math.random() * 1000000);
connections[clientNumber] = connection;
connection.on('close', function(reasonCode, description) {
delete connections[clientNumber];
});
console.log((new Date()) + ' Connection accepted. Client Number: ' + clientNumber);
});
// 处理来自 child_process 的消息
const dbChild = require('./dbChild');
dbChild.on('message', function(msg) {
if (connections[msg.cNum]) {
connections[msg.cNum].sendUTF(msg.msg);
}
});
性能考虑
- 使用对象存储连接可以避免遍历数组的性能开销,尤其是在用户数量较多时。
- 但是需要注意,频繁地生成和删除对象可能会增加垃圾回收的压力。
通过这种方式,可以有效地管理每个连接,并确保消息只发送给正确的用户。