为了账号安全,请及时绑定邮箱和手机立即绑定

设置 Socket.io 房间变量

设置 Socket.io 房间变量

长风秋雁 2023-11-02 21:05:42
我想在套接字空间变量中存储一些信息,但出现以下错误:UnhandledPromiseRejectionWarning: TypeError: Cannot set property 'host' of undefined这是我的代码:io.on('connection', (socket, next) => {    socket.on('create game', async () => {        console.log('Creating game...');        socket.username = await generateUsername();        socket.roomId = generateId();        socket.join(socket.roomId);        io.sockets.adapter.rooms[socket.roomId].host = socket.username;        io.sockets.adapter.rooms[socket.roomId].isOpen = true;        io.sockets.adapter.rooms[socket.roomId].players = [socket.username];        console.log('Game created! ID: ', socket.roomId);    });}如果我尝试记录socket.roomId它会返回类似rBAhx0. 当我登录时io.sockets.adapter.rooms,我得到以下信息:Map {  'PX_o3Di9sp_xsD6oAAAB' => Set { 'PX_o3Di9sp_xsD6oAAAB' },  'rBAhx0' => Set { 'PX_o3Di9sp_xsD6oAAAB' }}但是,当我尝试记录 时io.sockets.adapter.rooms[socket.roomId],它返回undefined。我怎样才能解决这个问题?
查看完整描述

3 回答

?
HUWWW

TA贡献1874条经验 获得超12个赞

Socket.io 在最新版本中进行了一些重大更改,无法像以前一样访问房间。它将很多对象和数组更改为映射和集合,您可以在您发布的日志中看到它。


Set对象是值的集合。您可以按插入顺序迭代集合的元素。Set中的一个值只能出现一次;它在套装系列中是独一无二的。


该Map对象保存键值对并记住键的原始插入顺序。任何值(对象和原始值)都可以用作键或值。


访问映射的属性与访问普通对象的属性的方式不同。例子:


const myMap = new Map();

myMap.set("foo", "bar");

console.log(myMap["foo"]) // undefined

console.log(myMap.get("foo")) // bar

同样适用于集合,但是在您的情况下,特别查询此集合可能是错误的方法,因为此集合仅包含 id 的集合,而不是实际的房间对象。即使您要从 Set 中获取值,您也无法访问它的属性(主机、isOpen 和玩家),因为它只是一个字符串。


恐怕 3.0 版本使得直接访问所有房间列表变得不可能了。然而,适配器现在有一个属性socketRooms,可以用来代替它。


为了更容易地访问套接字的房间,您应该像这样访问它们:


io.sockets.adapter.socketRooms(socketId);

然而,这仍然只会返回一个字符串列表。


此问题最简单的解决方案是在连接范围之外创建一个外部变量。


const rooms = {};


io.on('connection', (socket, next) => {

    socket.on('create game', async () => {

        console.log('Creating game...');

        socket.username = await generateUsername();


        socket.roomId = generateId();


        socket.join(socket.roomId);


        if (!rooms[socket.roomId]) rooms[socket.roomId] = {};

        rooms[socket.roomId].host = socket.username;

        rooms[socket.roomId].isOpen = true;

        rooms[socket.roomId].players = [socket.username];


        console.log('Game created! ID: ', socket.roomId);

    });

}


查看完整回答
反对 回复 2023-11-02
?
慕田峪9158850

TA贡献1794条经验 获得超7个赞

在从 Socket.io 更改ArrayMap. 一个简单的解决方案是改变:

    io.sockets.adapter.rooms[socket.roomId].host = socket.username;

到:

    io.sockets.adapter.get(socket.roomId).host = socket.username;


查看完整回答
反对 回复 2023-11-02
?
牛魔王的故事

TA贡献1830条经验 获得超3个赞

正如您在自己的日志中看到的,io.sockets.adapter.rooms是一个Map对象(在socket.io的更高版本中),而不是一个普通对象。这意味着房间是通过 访问的.get(),而不是通过简单的索引(例如您正在使用的索引)访问:

io.sockets.adapter.rooms[socket.roomId].host = socket.username;

这根本行不通,因为socket.roomId地图上没有普通属性。

如果你想获取房间对象,你必须这样做:

let roomObj = io.sockets.adapter.rooms.get(socket.roomId);
roomObj.host = socket.username;

在我看来,我不会直接弄乱房间里的物体。我们已经知道 socket.io 之前已经改变了他们的设计,将任何试图使用它们的代码渲染为损坏的并且需要重新设计。相反,我可能只是创建自己的数据结构,在其中存储自己的数据,然后我就不会依赖于 socket.io 如何改变其设计的突发奇想。直接访问房间对象不是socket.io 的承诺设计或承诺的API。他们可以随时改变它的工作方式,而且最近确实已经改变了它。


查看完整回答
反对 回复 2023-11-02
  • 3 回答
  • 0 关注
  • 194 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信