如何将 websocket 放入数据库(mongoDB/mongoose)?

Posted

技术标签:

【中文标题】如何将 websocket 放入数据库(mongoDB/mongoose)?【英文标题】:how to put websocket in to database (mongoDB/mongoose)? 【发布时间】:2020-03-20 17:41:12 【问题描述】:

当玩家登录时,我将他的 websocket 放入数据库(猫鼬混合)并保存。但是,经过一些测试,我了解到如果我将 websocket 放入数据库,websocket 变成了一堆数据并丢失了它的 websocket 属性并且不能向用户发送消息。另一方面,如果我将 websocket 放入数组中,我完全可以发送消息。无论如何要再次将“一堆数据”投射到 websocket 吗?因为我不想拥有一个容纳用户 websocket 的庞大数组。

app.js(我的服务器)

const express = require('express');
const  createServer  = require("http");
const mongoose = require('mongoose');
const config = require('./config');
const WebSocket = require('ws');
const activeUsers = require("./Models/ActiveUsersModel");
const app = express();

app.use(express.json());
app.use(express.urlencoded( extended: true ));
const server = createServer(app);
app.locals.wsArray = [];
app.use("/RegisterApi", require("./Routes/RegisterApi/RegisterApi"));
app.use("/MatchMakingApi", require("./Routes/MatchMakingApi/MatchMakerApi"));

const wss = new WebSocket.Server( server );



server.listen(config.PORT, function () 
    console.log(`im listening at $config.PORT`);
    mongoose.connect(config.MONGODB_URI, 
        useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true,
        useFindAndModify: false
    )

);
//function to split parameters from url
function getVars(tempVars) 
    var userObject = ;
    tempVars.forEach((a) => 
        var splited = a.split("=");
        userObject[splited[0]] = splited[1];
    );
    return userObject;


wss.on("connection",async (ws, request) => 

    console.log("Total connected clients: ", wss.clients.size);
    var tempVars = request.url.split("?")[1].split("&");
    var userObject = getVars(tempVars);

    console.log(userObject);
    const currentUser = await activeUsers.findOne( _id: userObject.parentID );
    console.log('user with id ' + currentUser.currentActiveUser._id + ' login');

    currentUser.webSocket = ws;
    await currentUser.markModified('webSocket');
    await currentUser.save();
    app.locals.wsArray.push(ws);


);


const db = mongoose.connection;

db.on('error', (err) => console.log(err))

活跃用户架构


const ActiveUsers = new schema(

    currentActiveUser: Users.schema,
    webSocket: mongoose.Mixed,
    isSearchingGame: 
        type: Boolean,
        default: false
    ,
    isInMatch: 
        type: Boolean,
        default: false
    

);

const ActiveUsersModel = mongoose.model("ActiveUsers", ActiveUsers);
module.exports = ActiveUsersModel;

匹配api(服务器中间件)发生错误的地方

router.post('/searchMatch'/*,verifyToken*/, async (req, res) => 


    const currentUserData = await activeUsers.findOne( _id: req.body.tempID );
    if (currentUserData.currentActiveUser.money < req.body.money)  res.send('insufficient money'); return; 

    req.app.locals.wsArray[0].send('aaaa'); // sends message
    await currentUserData.webSocket.send('aaaa'); // gets error " send() isnt a function"
);

【问题讨论】:

【参考方案1】:

您不能存储 Websocket 连接:您调用 ws 的对象作为您的 wss.on('connection' ...) 事件处理程序的第一个参数。您不能将它们存储在 MongoDB 中,也不能将它们序列化为 JSON:它们不是纯数据,而是您机器网络堆栈的接口。

因此,您需要在 nodejs 程序中维护它们。 Websocket 服务器 (wss) 有一个 clients 对象。你可以这样做

     wss.clients.forEach(...)

查看所有连接。您可以为您的连接添加属性,如下所示:

wss.on("connection", async (ws, request) => 
    ws.locals = 
    console.log("Total connected clients: ", wss.clients.size)
    var tempVars = request.url.split("?")[1].split("&")
    var userObject = getVars(tempVars)
    ws.locals.parentId = userObject.parentId
    const currentUser = await activeUsers.findOne( _id: userObject.parentID )

    wss.on("message", function (event) 
        /* retrieve the user */
        currentUser = await activeUsers.findOne( _id: this.locals.parentId)               
    )
)

这使您可以在收到传入消息时返回特定连接的用户。

【讨论】:

问题是客户端不发送消息。客户端发送用于匹配的http请求,在我的匹配api中,我将前5名玩家放在大厅并回复他们“搜索匹配”。当第6名玩家来时,我想使用websocket发送所有玩家匹配已准备好。如果我首先将他们的 websocket 放在数组中(如 webSocketArray[userID] = userWebsocket ),我可以做到这一点,但我有点想放入数据库。所以没有办法做到这一点?

以上是关于如何将 websocket 放入数据库(mongoDB/mongoose)?的主要内容,如果未能解决你的问题,请参考以下文章

WebSockets 不会从 Vue 应用程序发送数据 - 错误状态“发送”未定义,堆栈:Vue Express Mongo WebSockets

如何将多个 url 组合成一个 websocket?

从路由中发出 websocket 消息

Docker中的Spring Boot未连接到Docker中的Mongo

Spring Boot 中的多播 Websocket

Mongo:如何将所有使用 long timeStamp 的条目转换为 ISODate?