首页 > 解决方案 > Single Instance of socket.io is recognized as multiple Sockets in Backend

问题描述

Working on a project I occured the following problem. When listening for a "startGame"-Event in the Angular-Frontend my code didn't get executed eventhough I sent a message to the correct Room in the node-Backend. To make sure I don't have multiple Sockets I created a Singleton but it didn't help and the Backend still thinks there are multiple Sockets.

This is the Code: Angular: lobby.component.ts

import {ApplicationRef, ChangeDetectorRef, Component, Inject, NgZone, OnInit} from '@angular/core';
import {switchMap} from "rxjs/operators";
import {ActivatedRoute, ParamMap, Router} from "@angular/router";
import { DOCUMENT } from "@angular/common";
import {SocketService} from "../socket.service";
import {JsonObject} from "@angular/compiler-cli/ngcc/src/packages/entry_point";
import {SpotifyService} from "../spotify.service";

@Component({
  selector: 'app-lobby-component',
  templateUrl: './lobby.component.html',
  styleUrls: ['./lobby.component.scss']
})
export class LobbyComponent implements OnInit {
  lobbyId;
  lobbyinfo: any;

  constructor(@Inject(DOCUMENT) public document: Document, private route: ActivatedRoute, private router: Router, private socketService: SocketService, private spotifyService: SpotifyService) {
  }

  ngOnInit(): void {

    this.lobbyId = this.route.snapshot.paramMap.get("lobbyid");
    this.socketService.joinLobby(this.lobbyId, JSON.parse(localStorage.getItem('user')).id).subscribe((info) => {
      this.lobbyinfo = info;
      this.socketService.waitForGameStart(this.lobbyId);
    });

  }
...
}

Angular: socket.service.ts

import {Injectable} from '@angular/core';
import * as io from 'socket.io-client';
import {environment} from "./environment";
import {Observable} from "rxjs";
import {JsonObject} from "@angular/compiler-cli/ngcc/src/packages/entry_point";


@Injectable({
  providedIn: 'root'
})

export class SocketService {
  socket;
  question;
  lobbyinfo;

...

  getSocket() {
    if(!this.socket){
      this.socket = io(environment.SOCKET_ENDPOINT);
    }
    return this.socket;
  }


  joinLobby(lobbyId: string, userName: string) {
    this.getSocket().emit("joinLobby", {lobbyid: lobbyId, username: userName});
    this.getSocket().on('startGame', (msg) => {
      //do-Stuff
      //gets Executed because Socket is in the Room lobbyid
    });
  }

  waitForGameStart(lobbyId: any) {
    console.log("waitign for gamestart " + lobbyId);
    //Not executed because it isn't in the lobby
    this.getSocket().on('startGame', (msg) => {
      //do-Stuff
      //doesn't get executed even when previous call in joinLobby is commented out
    });
  }

}

Node: app.js

const uuidv4 = require('uuid/v4');
const express = require('express');
const app = express();
const path = require('path');
const dbConnection = require('./connections/mongoDB');

const APP_PORT = 5555;

const server = app.listen(APP_PORT, () => {
    console.log(`App running on port ${APP_PORT}`);
});

dbConnection.initConnection();

const io = require('socket.io').listen(server);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(express.static('public'));

app.get('/', (req, res) => {
    res.render('index');
});

// global-Chat
io.on('connection', (socket) => {

    ...

    socket.on('joinLobby', (msg) => {
        dbConnection.updateLobbyPlayers(msg.lobbyid, msg.username).then(() => {
            socket.join(msg.lobbyid);
            io.in(msg.lobbyid).emit('info', msg.username + " just joined this lobby.");
        });

    });

    socket.on('initGame', (msg) => {

        ...

        dbConnection.startGame(msg.lobbyid, tracks, possibleTracks).then(() => {
            io.in(msg.lobbyid).emit('startGame', {prepareTime: 10});
        });
    });

});

Note: To test the Method "waitForGameStart" I commented out the listener in "joinLobby" so the Message doesn't get catched right there.

Is there something I'm doing wrong? I feel like i don't fully understand the behaviour of sockets just yet. To me it seems like Node detects some weird differences between the two sockets and thinks they're not the same eventhough they are the same Instance.

In the worst case i'll just have to implement some kind of own "Room-Handling". Help would be appreciated, thanks

Edit: Added lobby.component.ts

Edit2: I don't get any error messages. I'm listening for messages in channel 'startGame'. I send the message with:

io.in(msg.lobbyid).emit('startGame', {prepareTime: 10});

in socket.on('initGame', ...

The problem is, that just the listener in joinLobby() gets the message. If I remove the listener in joinLobby(), the listener in waitForGameStart() still doesn't get the message. I assume that this happens, because Node recognizes both listeners as a different socket, but I'm not sure about it.

标签: node.jsangularsocketssocket.io

解决方案


推荐阅读