【问题标题】:Socket.io ID issue, wrong IDSocket.io ID 问题,ID 错误
【发布时间】:2020-08-11 16:52:49
【问题描述】:

首先要说我不是程序员,两天前我才学习了nodeJS、Jquery、AJAX、Socket.IO。如在,我根本不知道他们。

我正在尝试创建一个类似于 jackbox 的系统,并尽可能创建房间和添加玩家。但是 socket.id 出了点问题,它总是为我添加的每个玩家返回相同的 ID。这是遇到问题的代码(注意:房间创建是由统一调用的,这似乎工作得很好,因为房间代码和 id 的存储方式与它们应该完全一样):

var rooms = [];


//Check if socket is connected
io.on('connection',function(socket){
    console.log('made socket connection:'+socket.id);


      //if submit button is pressed on the login form
      app.post('/button', urlencodedParser, function(req, res){
      //check if a roomcode exists with the entered roomcode
      var found = rooms.some(el => el.roomcode === req.body.room);
      //if it exists
      if (found){
        //find the index in the room array of that room
        var targetindex = rooms.findIndex(element => element.roomcode === req.body.room);
        //send a message to that room in unity that you want to join
        io.to(rooms[targetindex].gamesocketid).emit('joinroom', {player: req.body.player, room: req.body.room, socket: socket.id});
        //add the player to the players array of that room
        rooms[targetindex].players.push({nickname: req.body.player, id: socket.id});
        //log the addition of the player to the console
        console.log('player ' + req.body.player + ' joined room ' + req.body.room + ' with socket ID ' + socket.id);
        //Log the room itself to the console
        console.log(rooms[targetindex]);
        //send a response with the data. to tell you successfully added the player to ajax
        res.json(rooms[targetindex]);
      } else {
        console.log('room not found');
      }
    });



    socket.on('createroom',function(data){
      JSON.stringify(data);
      console.log('Game with socket id ' + socket.id + ' created a room with room code ' + data.roomcode );
      var players = [];
      rooms.push({roomcode: data.roomcode, gamesocketid: socket.id, players: players});
      console.log(rooms);
      //console.log('room code ' + RoomJSON.roomcode);
    });

    socket.on('destroyroom',function(data){
      JSON.stringify(data);
      console.log('Destroy a room with room code ' + data.roomcode );
      rooms = rooms.filter(function(value){
        return value.roomcode !== data.roomcode;
      });
    });


});

我很确定,我可能正在做一些不允许的事情。我认为这可能与尝试从 io.on('connection' 中运行 app.post 相关,如果是这种情况,我对如何解决它有点迷茫。我需要播放器的 socket.id存储在我的数组中,以便我以后可以使用这些 ID 发送重要的游戏数据。

我的控制台日志(请注意此日志中的所有 ID 都相同,但并非总是如此):

    PS D:\nodejs\Projects\ZoomFriends> nodemon app
[nodemon] 2.0.3
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
made socket connection:Fe9o3x5-_e1osj5sAAAA
Game with socket id Fe9o3x5-_e1osj5sAAAA created a room with room code JBYK
[
  {
    roomcode: 'JBYK',
    gamesocketid: 'Fe9o3x5-_e1osj5sAAAA',
    players: []

  }
]
made socket connection:6sjC6WMGyky2G5-sAAAB
Fe9o3x5-_e1osj5sAAAA
player Sebastiaan Phone joined room JBYK with socket ID Fe9o3x5-_e1osj5sAAAA
{
  roomcode: 'JBYK',
  gamesocketid: 'Fe9o3x5-_e1osj5sAAAA',
  players: [ { nickname: 'Sebastiaan Phone', id: 'Fe9o3x5-_e1osj5sAAAA' } ]
}
made socket connection:sZFzMaIow5TVCf4dAAAC
Fe9o3x5-_e1osj5sAAAA
player Sebastiaan Browser joined room JBYK with socket ID Fe9o3x5-_e1osj5sAAAA
{
  roomcode: 'JBYK',
  gamesocketid: 'Fe9o3x5-_e1osj5sAAAA',
  players: [
    { nickname: 'Sebastiaan Phone', id: 'Fe9o3x5-_e1osj5sAAAA' },
    { nickname: 'Sebastiaan Browser', id: 'Fe9o3x5-_e1osj5sAAAA' }
  ]
}

为了完成主义者,我将添加其他方面: app.js:

//Set up express
var express = require('express');

//Set up socket.io
var socket = require('socket.io')//({transports: ['websocket'],});

//create an express app to talk to
var app = express();

//Include the controller
var zoomFriendsController = require('./controllers/zoomFriendsController');

//set up view-template engine
app.set('view engine', 'ejs');

//allow static files
app.use(express.static('./public'));

//listen to a port and start the server
var server = app.listen(4000);
console.log('listening to port 4000');

// Socket Setup
var io = socket(server);

//fire the controller
zoomFriendsController(app,io);

rooms.ejs

<!DOCTYPE html>
<html>
  <head>
    <title>Todo List</title>
    <script
      src="https://code.jquery.com/jquery-3.5.0.min.js"
      integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ="
      crossorigin="anonymous"></script>
    <link href="/assets/styles.css" rel="stylesheet" type="text/css" />
    <script src="/assets/zoomFriendsAjax.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.js"></script>
  </head>
  <body>
    <script src="/assets/sockets.js"></script>
    <h2>Welcome To ZoomFriends</h2>

    <div id="pagecontent">
      <div id="serverform">
        <form>
          <label for="servercode"><strong>Server Code:</strong></label>
          <input type="text" id="servercodeinput" name="servercode" placeholder="Insert your server code here..." required>
          <label for="nickname"><strong>Your Nickname</strong></label>
          <input type="text" id="nickname" name="nickname" placeholder="Insert your nickname here..." required>
          <button type=submit>join room</button>
        </form>
      </div>
      <div id="connpage">
        <h2>Connected to server</h2>
        <button id=startgame>Start Game if all players have joined!</button>
      </div>
      <div id="gamepage">
        <h2>Game is Started</h2>
      </div>
    </div>
  </body>
</html>

zoomFriendsAjax.js

$(document).ready(function(){


  $('#serverform').on('submit', function(){

      var player = $('input[type="text"]#nickname');
      var room = $('input[type="text"]#servercodeinput');
      var joindata = {player: player.val(), room: room.val().toUpperCase()};

      $.ajax({
        type: 'POST',
        url: '/button',
        data: joindata,
        success: function(data){
          //do something with the data via front-end framework
          //location.reload();
          //alert('button pressed');

          serverconnected();

        }
      });




      return false;

  });

  $('#startgame').on('click', function(){
    //alert('button pressed');
    var started = true;

    $.ajax({
      type: 'POST',
      url: '/start',
      data: started,
      success: function(data){
        //do something with the data via front-end framework
        //location.reload();
        gamestarted();

      }
    });

    return false;
  });

  function serverconnected(){
    $('#connpage').show();
    $('#serverform').hide();
  }

  function gamestarted(){
    alert('gamestarted function happening');
    $('#gamepage').show();
    $('#connpage').hide();
  }

  function nosuchroom(){
    alert('Wrong Room Name');
  }

});

styles.css

body{
    background: #0d1521;
    font-family: tahoma;
    color: #989898;
    text-align: center;
}

#todo-table{
    position: relative;
    width: 95%;
    background: #090d13;
    margin: 0 auto;
    padding: 20px;
    box-sizing: border-box;
}

#todo-table form:after{
    margin: 0;
    content: '';
    display: block;
    clear: both;
}

#connpage{
    display: none;
}

#gamepage{
    display: none;
}
#servercodeinput{
    text-transform: uppercase;
}

input::placeholder {
  font-style: italic;
}

input[type="text"]{
    width: 100%;
    padding: 20px;
    background:#181c22;
    border: 0;
    float: left;
    font-size: 20px;
    color: #989898;
    text-align: center;
}

label{
    width: 100%;
    padding: 20px;
    background:#23282e;
    border: 0;
    float: left;
    font-size: 20px;
    color: #989898;
    text-align: center;
}

button{
    padding: 20px;
    width: 100%;
    float: left;
    background: #23282e;
    border: 0;
    box-sizing: border-box;
    color: #fff;
    cursor: pointer;
    font-size: 80px;
}

ul{
    list-style-type: none;
    padding: 0;
    margin: 0;
}

li{
    width: 100%;
    padding: 20px;
    box-sizing: border-box;
    font-family: arial;
    font-size: 20px;
    cursor: pointer;
    letter-spacing: 1px;
}

li:hover{
    text-decoration: line-through;
    background: rgba(0,0,0,0.2);
}

h1{
    background: url(/assets/logo.png) no-repeat center;
    margin-bottom: 0;
    text-indent: -10000px;
    text-align: center;
}

sockets.js

//make connection
var socket = io.connect('95.97.158.61:4000');

最后是完整的 ZoomFriendsController.js:

var bodyParser = require('body-parser');
var mongoose = require('mongoose');

//Connect to database
mongoose.connect('mongodb+srv://SebastiaanVW:Test1234@todo-m1zp6.mongodb.net/test?retryWrites=true&w=majority', { useNewUrlParser: true , useUnifiedTopology: true })

//Create a schema - this is a blueprint
var roomSchema = new mongoose.Schema({
  room: String
  //players: Array
});

//create a model
var Rooms = mongoose.model('Room', roomSchema)

var urlencodedParser = bodyParser.urlencoded({extended: false});

//Start Functions
module.exports = function(app,io){

var rooms = [];
var myroomindex = -1;

//Check if socket is connected
io.on('connection',function(socket){
    console.log('made socket connection:'+socket.id);


      //if submit button is pressed on the login form
      app.post('/button', urlencodedParser, function(req, res){
      console.log(socket.id);
      //put the player data in message variable
      //var message = req.body.player;
      //check if a roomcode exists with the entered roomcode
      var found = rooms.some(el => el.roomcode === req.body.room);
      //if it exists
      if (found){
        //find the index in the room array of that room
        var targetindex = rooms.findIndex(element => element.roomcode === req.body.room);
        //send a message to that room in unity that you want to join
        io.to(rooms[targetindex].gamesocketid).emit('joinroom', {player: req.body.player, room: req.body.room, socket: socket.id});
        //add the player to the players array of that room
        rooms[targetindex].players.push({nickname: req.body.player, id: socket.id});
        //log the addition of the player to the console
        console.log('player ' + req.body.player + ' joined room ' + req.body.room + ' with socket ID ' + socket.id);
        //Log the room itself to the console
        console.log(rooms[targetindex]);
        //send a response with the data. to tell you successfully added the player to ajax
        res.json(rooms[targetindex]);
      } else {
        console.log('room not found');
        res.json(rooms[targetindex]);
      }
    });

    //if submit is pressed on the startgame button
    app.post('/start', urlencodedParser, function(req, res){
        console.log('game started');
        var goingwell = true;
        io.to(rooms[myroomindex].gamesocketid).emit('gamestarted',{started: true});
        rooms[myroomindex].players.forEach(function(item,i){
          var tempsocket = rooms[myroomindex].players[i].socket
          console.log(tempsocket);
          io.to(tempsocket).emit('gamestarted',{started: true});
        });
        res.json(goingwell);
    });

    socket.on('createroom',function(data){
      JSON.stringify(data);
      console.log('Game with socket id ' + socket.id + ' created a room with room code ' + data.roomcode );
      var players = [];
      rooms.push({roomcode: data.roomcode, gamesocketid: socket.id, players: players});
      console.log(rooms);
      //console.log('room code ' + RoomJSON.roomcode);
    });

    socket.on('destroyroom',function(data){
      JSON.stringify(data);
      console.log('Destroy a room with room code ' + data.roomcode );
      rooms = rooms.filter(function(value){
        return value.roomcode !== data.roomcode;
      });
    });

    socket.on('gamestarted',function(data){
        //res.render('gamestarted');
        console.log('recieved gamestarted');
    });
});



app.get('/', function(req, res){
  res.render('rooms');
});

};

我知道其中有很多我还没有使用的东西,还有一些不起作用的东西,比如 myroomindex 值。但现在我需要解决 socketid 问题。基本上我所有的玩家都在我的阵列中获得相同的套接字 ID。感谢您的观看!

【问题讨论】:

  • 可能与服务器和客户端有关。也许......我不知道,这东西对我来说是新的,我只是把这东西拼凑在一起......

标签: jquery node.js ajax express socket.io


【解决方案1】:

您不能将app.post('/button', ...) 放入io.on('connection', ...)。不能那样构建它。这意味着每次获得新的 socket.io 连接时,都会添加一个额外的重复 app.post() 处理程序。然后,无论何时该路由被击中,他们都将竞争该路由,并且只有安装的第一个将获胜,因此无论哪个客户端发送 POST 请求,它将始终使用曾经连接的第一个 socket.id。

您必须记住,app.xxx() 为所有用户注册路由,并且它们在您的服务器生命周期内是永久的。它们不仅适用于刚刚与 socket.io 连接的用户。

相反,您需要将app.post() 移到io.on('connection, ...) 之外,这里有一些选项:

  1. 从客户端发送带有 POST 数据的 socket.id(不是特别理想,因为它可能被欺骗)。
  2. 从 socket.io cookie 中获取它(如果可以的话)。
  3. 当 socket.io 连接连接时,你自己将它保存在一个 cookie 中,然后你可以在获得 app.post() 时从该 cookie 中获取它
  4. 不要使用表单发布。只需在 socket.io 消息中发送数据,然后您就会知道它是哪个套接字。

我最喜欢的可能是#4。

【讨论】:

  • 谢谢,这是我的预期,但很高兴有更有经验的人可以为我澄清。当您说不要使用表单发布时,这将如何工作,我需要一个玩家姓名、房间号以及 socket.id 才能来回发送消息并知道我在说谁。你能澄清一下这个无后版本是如何工作的吗?
  • @SebastiaanvanWaardenberg - 您仍然创建相同的 HTML 表单,但是当用户按下发送或调用任何按钮时,您不会发布表单。相反,您可以使用客户端 Javascript 从表单元素中获取数据值,将它们放入一个对象中,然后通过 socket.io 消息将该数据发送到您的服务器。当你的服务器收到消息时,它会确切地知道它来自哪个socket.io socket和socket.id。
猜你喜欢
  • 1970-01-01
  • 2012-04-05
  • 2017-11-29
  • 2016-12-16
  • 1970-01-01
  • 2015-06-01
  • 2019-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多