【问题标题】:Node.JS Socket.IO application client identification issue. All clients appear with same id as last connected clientNode.JS Socket.IO 应用程序客户端识别问题。所有客户端的 ID 都与上次连接的客户端相同
【发布时间】:2016-01-20 11:05:38
【问题描述】:

我正在尝试构建一个简单的系统,将某些详细信息附加到客户,例如昵称、国家/地区等,但我偶然发现了有关信息未正确注册的问题。

请看我的代码:

index.js

var express = require('express'),
    app = express(),
    server = require('http').Server(app),
    io = require('socket.io')(server),

    glob = require('glob'),
    path = require('path'),
    fs = require('fs'),

    satelize = require('satelize');

var chat = require(__dirname + '/inc/chat');

server.listen(8888);

app.use('/public', express.static(path.join(__dirname, 'public')));

app.get('/', function (req, res) {
    res.sendFile(__dirname + '/views/index.html');
});

io.on('connection', function (socket) {
    chat.init(satelize,socket, function () {
        var client = chat.fetchClient(socket.id);
        socket.emit('client info', client);
        socket.on('message', function (msg) {
            console.log('Message recieved from ' + client.id);
            socket.emit('client info', client);
        });
        socket.on('disconnect', function () {
            chat.removeClient(client);
        });
    });
});

/inc/chat.js

module.exports = {

    /* client object initialization */
    client : {
        id          : null,
        username    : null,
        geo         : null
    },

    /* client array initialization */
    clients: [],

    init: function (satelize, socket, callback) {
        var init = this;
        if (typeof callback == "function") {
            var client = this.client;
            client.id = socket.id;
            satelize.satelize( { ip : this.ip(socket ) }, function(error, payload) {
                client.geo = payload;
                init.addClient(client);
                callback();
            });
        }
    },

    /* information retrieval*/
    ip: function (socket) {
        return cleanIp(socket.handshake.address)
    },

    /* client (the user) stuff */
    addClient: function (client) {
        if (client.id !== null) {
            this.clients.push(client);
            console.log(client.id + ' added to clients.');  
        } else {
            console.log('Cannot add client: id (null)');
        }
    },
    fetchClient: function (id) {
        for (var i = 0; i < this.clients.length; i++) {
            if(this.clients[i].id == id) {
                return this.clients[i];
            }
        }
    },
    removeClient: function (client) {
        console.log('removing client: ');
        console.log(client.id);
        var found = null;
        for (var i = 0; i < this.clients.length; i++) {
            if (this.clients[i] == client) {
                this.clients.splice(i,1);
                found = this.clients[i];
                break;
            }
        }
        if (this.clients.length > 0) {
            console.log('client list after removal: ');
            for (var i = 0; i < this.clients.length; i++) {
                console.log(this.clients[i].id);
            }
        } else {
            console.log('No clients in client array.');
        }
    }
}

function cleanIp (ip) {
    return ip.replace('::ffff:','');
}

在 index.html 中,我有以下 js 用于 id 和消息的可视化表示:

    var socket = io();
    socket.on('client info', function (data) {
        $('.client-id').text(data.id);
    });

    $('#input').keydown(function(e) {
        var key = e.which;
        if (key == 13) {
            if ($(this).val().length > 0) {
                socket.emit('message', $(this).val());
                $(this).val('');
            }
        }
    });

好的,如果我启动这个简单的节点服务器并在三个不同的浏览器选项卡中打开页面而不发送任何消息,那么 id 似乎是正确的。

但只要我从其中一个浏览器选项卡发送消息,它就会采用最后连接的客户端 ID。

当服务器启动时,它会在控制台中输出以下内容:

[nodemon] starting `node index.js`
/#h9sraEo5c8uLKgczAAAA added to clients.
/#opAfZCrRa64gFsR7AAAB added to clients.
/#x-WfhClfNsLEWE85AAAC added to clients.

如果我刷新第一个标签:

removing client:
/#x-WfhClfNsLEWE85AAAC
client list after removal:
/#x-WfhClfNsLEWE85AAAC
/#x-WfhClfNsLEWE85AAAC
/#pdlKD-v3K15_2voZAAAD added to clients.

如果我从该选项卡发送消息:

Message recieved from /#pdlKD-v3K15_2voZAAAD

如果我现在切换到另一个选项卡并写一条消息,服务器会输出与上面相同的消息,并更改浏览器中 id 的视觉表示。

为什么连接的客户端的id会变成最后连接的客户端的id?

【问题讨论】:

    标签: javascript node.js socket.io


    【解决方案1】:

    问题是从line 4, chat.js 开始的客户端对象正在被重用,而没有重置细节,导致数据不是唯一的。

    在删除对象并从line 16, chat.js 开始动态生成它之后,解决了所有关于所有 id 都是最后一个的已知问题。

    以下是更新后的脚本:

    index.js

    var express = require('express'),
        app = express(),
        server = require('http').Server(app),
        io = require('socket.io')(server),
    
        glob = require('glob'),
        path = require('path'),
        fs = require('fs'),
    
        satelize = require('satelize');
    
    var chat = require(__dirname + '/inc/chat');
    
    server.listen(8888);
    
    app.use('/public', express.static(path.join(__dirname, 'public')));
    
    app.get('/', function (req, res) {
        res.sendFile(__dirname + '/views/index.html');
    });
    
    io.on('connection', function (socket) {
        socket.id = chat.uniqueId();
        chat.init(satelize,socket, function () {
            var client = chat.fetchClient(socket.id);
            socket.emit('client info', client);
            socket.on('message', function (msg) {
                console.log(client.id + ' sent: ' + msg);
                socket.emit('client info', client);
            });
            socket.on('disconnect', function () {
                chat.removeClient(client);
            });
        });
    });
    

    聊天.js

    module.exports = {
    
        /* client array initialization */
        clients: [],
    
        init: function (satelize, socket, callback) {
            var init = this;
            if (typeof callback == "function") {
                var client = {
                    id : null,
                    username: null,
                    geo : null
                }
                client.id = socket.id;
                satelize.satelize( { ip : this.ip(socket ) }, function(error, payload) {
                    client.geo = payload;
                    var exists = null;
                    if (init.clients.length > 0) {
                        for (var i = 0; i < init.clients.length; i++) {
                            if(init.clients[i].id == client.id) {
                                exists = client.id;
                            }
                        }
                    }
                    if (exists == null) {
                        init.addClient(client); 
                    }
                    callback();
                });
            }
        },
    
        /* information retrieval*/
        ip: function (socket) {
            return cleanIp(socket.handshake.address)
        },
    
        /* client (the user) stuff */
        addClient: function (client) {
            if (client.id !== null) {
                this.clients.push(client);
                console.log(client.id + ' added to clients.');  
            } else {
                console.log('Cannot add client: id (null)');
            }
        },
        fetchClient: function (id) {
            for (var i = 0; i < this.clients.length; i++) {
                if(this.clients[i].id == id) {
                    return this.clients[i];
                }
            }
        },
        removeClient: function (client) {
            console.log('removing client: ' + client.id);
            var found = null;
            for (var i = 0; i < this.clients.length; i++) {
                if (this.clients[i] == client) {
                    this.clients.splice(i,1);
                    found = this.clients[i];
                    break;
                }
            }
            if (this.clients.length > 0) {
                console.log('client list after removal: ');
                for (var i = 0; i < this.clients.length; i++) {
                    console.log(this.clients[i].id);
                }
            } else {
                console.log('No clients in client array after last removal.');
            }
        },
    
        uniqueId : function() {
            function s4() {
                return Math.floor((1 + Math.random()) * 0x10000)
                .toString(16)
                .substring(1);
            }
            return s4() + s4() + '-' + s4() + '-' + s4() + s4();
        }
    
    }
    
    function cleanIp (ip) {
        return ip.replace('::ffff:','');
    }
    

    【讨论】:

      【解决方案2】:

      我在 index.js 中您的socket.on('message') 事件,您从回调中获得msg,但您使用的是具有当前客户端的client。 而是使用msg 变量,例如:

         socket.on('message', function (msg) { 
              //msg holds the client
              console.log('Message recieved from ' + msg.clientId);
              socket.emit('client info', client);
          });
      

      并从客户端发送clientId,例如:

      var id = socket.socket.sessionid;
      socket.emit('message', {message: $(this).val(), clientId: id);
      

      注意:此 sessionid 与服务器 clientid 不同。

      【讨论】:

      • 参数保存从客户端发送的实际消息,可以是任何内容,在本例中是来自输入元素的字符串。我不希望从客户端传递服务器使用和 id,因为这样可以操纵系统。因此,通过使用实际的套接字,我可以通过其 id 在阵列服务器端查找客户端详细信息。至少那是我的计划,但显然有些不对劲。感谢您查看它,但这是错误的。
      • 对不起。 msg 消息本身具有 clientid 属性。再次检查答案。
      • 我必须确认一下,msg 变量只保存来自#input 的值。请参阅:socket.emit( 'message', $(this).val() ); 如果我 console.log 的 msg 变量服务器端它只包含代表 #input 元素值的字符串。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-15
      • 2015-06-21
      • 2011-01-27
      • 1970-01-01
      • 2011-03-17
      • 1970-01-01
      • 2022-06-13
      相关资源
      最近更新 更多