动态命名空间 Socket.IO

Posted

技术标签:

【中文标题】动态命名空间 Socket.IO【英文标题】:Dynamic Namespaces Socket.IO 【发布时间】:2012-10-20 02:02:07 【问题描述】:

如何在 socket.io 中使用动态命名空间。

我正在查看(可怜的)documentation,它说必须像这样使用命名空间:

io.of('/news')

io.of('/akfda')

要使用命名空间,请执行io.of("/namespace")

我需要在服务器中注册每个命名空间吗?也许我想要一个动态内容的命名空间。

我该怎么做:

io.of('/:somethign/:id')

【问题讨论】:

***.com/questions/10004616/… 从阅读文档和一些谷歌搜索来看,socket.io 似乎没有这个功能。见这里:***.com/questions/15732678/… 【参考方案1】:

从版本 2.1.1 开始,我能够使它与此一起使用:

wss.of((nsp, query, next) => 
  const  token  = query;

  // Do your authentication or whatever here...

  // If success
  next(null, true);

).on('connect', (socket) => 
  // socket connected to your namespace
);

【讨论】:

是的,它在文档中就是这样。但是这些参数(nsp、query、next)是从哪里来的呢?我不明白。 好的,我想我现在明白了。将 .of() 与正则表达式或函数一起使用使其自动侦听连接到匹配的命名空间名称并随后创建它..【参考方案2】:

服务器

var MAX_CLIENTS = 5;
var namespace_queue = [];

function searchObjectOnArray(nameKey, myArray) 
    for (var i = 0; i < myArray.length; i++) 
        if (myArray[i].id === nameKey) 
            return myArray[i];
        
    


function createNamespace(data)
    var ns = 
                //id: require('node-uuid')(),
                id : data.name,
                clients: 0, 
            ;

    namespace_queue.push(ns);

    return ns;


createNamespace(name: 'primer');

io.of('').on('connection', function(socket)     

    console.log('-' + socket.id);

    /// Welcome to the new client
    socket.emit('Welcome', SocketId : socket.id);

    socket.on('JoinToApp', function (data, callback) 
        var namespaceToConnect = searchObjectOnArray(data.namespace, namespace_queue)
        if(namespaceToConnect.clients <= MAX_CLIENTS)
            var dynamicNamespace = io.of('/' + namespaceToConnect.id);

            dynamicNamespace.on('connection', function(ns_socket)
                    console.log('user connected to ' + namespaceToConnect.id);
                    dynamicNamespace.emit('hi', 'everyone!');
                );

            namespaceToConnect.clients++;  
                  

        callback(namespaces:namespace_queue);
    )

    socket.on('createNamespace',function(data,join_cb)

        createNamespace(data);

        join_cb(message:'Namespace created');
    ); 
);

客户

<input id="namespaceInput" type="text" placeholder="New namespace name">
<input id="namespaceToConnect" type="text" placeholder="namespace to connect">

<button onclick="javascript: createNamespace()">Create Namespace</button>
<button onclick="javascript: joinToNamespace()">Connect to Namespace</button>

<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script>
    var socket = null;
   (function()
       socket = io.connect('http://localhost:3000/');        
   )()

   function createNamespace()
       var namespaceName = document.getElementById("namespaceInput").value;
       socket.emit('createNamespace', name : namespaceName, function(data)
           alert(data.message);
       )
   

   function joinToNamespace()
       var name = document.getElementById("namespaceToConnect").value;
       socket.emit('JoinToApp', namespace: name, function(data)
            console.log('Namespaces created:');
            console.log(data)

            var ns_socket = io.connect('http://localhost:3000/' + name);
            ns_socket.on('connect',function()
                console.log('joined namespace ' + name);
            );

            ns_socket.on('hi', function(data)
                console.log('hi ' + data)
            )
        );

   
</script>

更多详情:https://ingcamilorodriguez.wordpress.com/2016/06/21/como-hacer-namespaces-dinamicos-en-socket-io/

【讨论】:

【参考方案3】:

我会使用“房间”来支持您的动态内容。

服务器端

var server = require('http').createServer(),
    io     = require('socket.io')(server);


io.on('connection', function(socket)

  var room = socket.handshake['query']['r_var'];

  socket.join(room);
  console.log('user joined room #'+room);

  socket.on('disconnect', function() 
    socket.leave(room)
    console.log('user disconnected');
  );

  socket.on('chat message', function(msg)
    io.to(room).emit('chat message', msg);
  );

);

server.listen(3000);

客户端

var socket_connect = function (room) 
    return io('localhost:3000', 
        query: 'r_var='+room
    );


var random_room = Math.floor((Math.random() * 2) + 1);
var socket      = socket_connect(random_room);

socket.emit('chat message', 'hello room #'+random_room);
....

【讨论】:

在与命名空间斗争了几个小时后,我终于解决了房间问题! 但是您不能将房间添加到您的房间。 非常有帮助。谢谢!【参考方案4】:

这是一种方法。这是我为解决问题而创建的 socket.io 子类:

https://github.com/PencilCode/dynamic.io

该子类添加了动态命名空间以及虚拟主机名支持(如果您愿意,每个主机都可以进入自己的命名空间树)。该仓库有一些示例。

这是一个通用的 socket.io 监听器,它监听每个请求的命名空间,并为每个连接的套接字记录一条消息。您可以使用不同的正则表达式来监听命名空间的任何子集。

它无需任何修改即可与标准 socket.io 客户端库一起使用。

var DynamicServer = require('dynamic.io'); io = 动态服务器( host: true, // 启用虚拟主机处理 publicStatus: true // 启用 /socket.io/status 页面。 ); // 可以设置任意数量的命名空间模式。 // 这是一个单一的包罗万象模式的例子。 io.setupNamespace(/.*/, function(nsp) nsp.on('connect', function(socket) console.log('一个连接的套接字', nsp.fullname()); ); nsp.expire(函数() console.log(nsp.fullname(), '即将到期'); ); ); io.listen(8888);

【讨论】:

因为您要保持命名空间名称与命名空间实例的本地映射。当我们将实例从 1 扩展到 n 时,这将如何表现。我们可以将命名空间实例保存在 redis 中,并使用它的名称进行缩放。【参考方案5】:

Socket.IO 支持“房间”(https://github.com/LearnBoost/socket.io/wiki/Rooms),您可以使用它来代替命名空间。此外,当您需要动态路由时(并且您在应用程序中使用 express) - 最好的方法是使用 express box 中的路由引擎。

Best way to do dynamic routing with Express.js (node.js) Using routes in Express-js http://expressjs.com/api.html#app.routes http://shtylman.com/post/expressjs-re-routing/ http://jordanhoff.com/post/22602013678/dynamic-express-routing

但是,如果您仍然认为在 socket.io 中的命名空间中需要动态,这里是如何实现它的小示例:

用户端:

var connect = function (ns) 
    return io.connect(ns, 
       query: 'ns='+ns,
       resource: "socket.io"
    );


var socket = connect('/user/12');

服务器端:

var url = require('url');
  , ev = new events.EventEmitter()

// <ns name>: <ns regexp>
var routes = 
  // /user/:id
  'user': '^\\/user\\/(\\d+)$',

  // /:something/:id
  'default': '^\\/(\\\w+)\\/(\\d+)$'
;

// global entry point for new connections
io.sockets.on('connection', function (socket) 
  // extract namespace from connected url query param 'ns'
  var ns = url.parse(socket.handshake.url, true).query.ns;
  console.log('connected ns: '+ns)

  //
  for (var k in routes) 
    var routeName = k;
    var routeRegexp = new RegExp(routes[k]);

    // if connected ns matched with route regexp
    if (ns.match(routeRegexp)) 
      console.log('matched: '+routeName)

      // create new namespace (or use previously created)
      io.of(ns).on('connection', function (socket) 
        // fire event when socket connecting
        ev.emit('socket.connection route.'+routeName, socket);

        // @todo: add more if needed
        // on('message') -> ev.emit(...)
      );

      break;
    
  

  // when nothing matched
  // ...
);

// event when socket connected in 'user' namespace
ev.on('socket.connection route.user', function () 
  console.log('route[user] connecting..');
);

// event when socket connected in 'default' namespace
ev.on('socket.connection route.default', function () 
  console.log('route[default] connecting..');
);

希望对你有帮助!

【讨论】:

您能否再次解释一下您的示例。我也在做同样的事情,我认为它非常有用,但我不明白你是如何做你正在做的事情的。 我不确定这是什么时候添加的,但现在您可以使用命名空间名称的正则表达式:socket.io/docs/server-api/#server-of-nsp

以上是关于动态命名空间 Socket.IO的主要内容,如果未能解决你的问题,请参考以下文章

Socket.io 命名空间限制以及如何扩展它

socket.io切换命名空间

我可以在 socket.io 的命名空间中使用房间吗

socket.io笔记三之子命名空间的socket连接

socket.io - 如何在命名空间上广播消息?

使用 socket.io-client.java 库连接到 socket.io 命名空间