关于WebSocket-Node模块的Session改造[更新0.2]
发布于 11 年前 作者 bigmusic 5290 次浏览 最后一次编辑是 8 年前

整条知识链已建立好,剩下就是慢慢把整体描画完整,一边补充知识点了; 课题是建立一个自己的框架,暂定目标是基于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
1 回复

为什么websocket-node到现在还没有加入session,这样我就没办法处理单聊啊,求指导

回到顶部