Node.js Socket.io - 服务器 setInterval 以半速运行,仅在调用 socket.on 时全速运行

时间:2021-02-18 00:51:10

标签: javascript node.js socket.io

我的服务器表现得很奇怪 -- setInterval 下的更新 Update LOBBIES 设置为 @ 1000/60ms 或 60cps,我只得到稳定的 34cps。但是当从 socket.emit('angle') 侧使用 CLIENT 时,它以 60cps 平稳运行,直到 socket.emit('angle') 停止,然后返回到 34cps。已经3天了,我仍然完全不知道。代码似乎没有节流问题,而且奇怪的是,当只为 socket.on 而不是其他人调用 angle 事件时,效果会更好。没有任何意义!有什么想法吗?

HTML/Javascript 客户端

User.onConnect = (socket) => {  
    var lobbies = [];
    socket.on('updateLobbies', (data) => {
        $('#menu-screen-navigation-display-play ul').empty();
        $('#menu-screen-navigation-display-play ul').append(
            "<li style='position: fixed;top: calc(13vh); width: 47.5%; height: calc(5vh); left:26.25%;background-color: rgba(50,50,50,1);'>" +
            "   <table>" +
            "       <th style='width:10%'>" +
            "           <span></span>" +
            "       </th>" +
            "       <th style='width:20%'>" +
            "           <span class='play-lobby'>Lobby</span>" +
            "       </th>" +
            "       <th style='width:20%'>" +
            "           <span class='play-map'>Map</span>" +
            "       </th>" +
            "       <th style='width:20%'>" +
            "           <span class='play-gamemode'>Game Mode</span>" +
            "       </th>" +
            "       <th style='width:15%'>" +
            "           <span class='play-players'>Players</span>" +
            "       </th>" +
            "       <th style='width:15%'>" +
            "           <span></span>" +
            "       </th>" +
            "   </table>" +
            "</li>");
        $('#menu-screen-navigation-display-play ul').append(
            "<li style='position: fixed;bottom: calc(4vh); width: 47.5%; height: calc(5vh); left:26.25%;background-color: rgba(50,50,50,1);'>" +
            "   <table>" +
            "       <th style='width:10%'>" +
            "           <span></span>" +
            "       </th>" +
            "       <th style='width:20%'>" +
            "           <span class='play-lobby'></span>" +
            "       </th>" +
            "       <th style='width:20%'>" +
            "           <span class='play-map'></span>" +
            "       </th>" +
            "       <th style='width:20%'>" +
            "           <span class='play-gamemode'></span>" +
            "       </th>" +
            "       <th style='width:15%'>" +
            "           <span class='play-players'></span>" +
            "       </th>" +
            "       <th style='width:15%'>" +
            "           <span></span>" +
            "       </th>" +
            "   </table>" +
            "</li>");
        for(let i in data){
            lobbies[i] = data[i];
            
            switch(lobbies[i].mode){
                case 'Outbreak': {
                    lobbies[i].modeColor = 'green';
                    
                    break;
                }
                default: {
                    lobbies[i].modeColor = 'white';
                }
            }           
            switch(lobbies[i].map){
                case 'Urban Delight': {
                    lobbies[i].mapSrc = 'img/ui/map-icons/urbanDelight.png';
                    
                    break;
                }
                default: {
                    break;
                }
            }
            
            $('#menu-screen-navigation-display-play ul').append(
                "<li>" +
                "   <table>" +
                "       <th style='width:10%'>" +
                "           <img src='" + lobbies[i].mapSrc + "'/>" +
                "       </th>" +
                "       <th style='width:20%'>" +
                "           <span class='play-lobby'>" + lobbies[i].title + "</span>" +
                "       </th>" +
                "       <th style='width:20%'>" +
                "           <span class='play-map'>" + lobbies[i].map + "</span>" +
                "       </th>" +
                "       <th style='width:20%'>" +
                "           <span class='play-gamemode' style='color:"+lobbies[i].modeColor+"'>" + lobbies[i].mode + "</span>" +
                "       </th>" +
                "       <th style='width:15%'>" +
                "           <span class='play-players'>" + lobbies[i].online + " / " + lobbies[i].max + "</span>" +
                "       </th>" +
                "       <th style='width:15%'>" +
                "           <button id='"+ lobbies[i].title + "' class='bubble'>Join</button>" +
                "       </th>" +
                "   </table>" +
                "</li>");
                
            $('#'+lobbies[i].title).click(function(){
                playAudio(SFX['pop']);
                socket.emit('lobby.join', this.id);
                $('#menu-screen').hide();
                $('#menu-canvas').hide();
                $('#game-screen').show();
                MUSIC['menu'].pause();
                MUSIC['menu'].currentTime = 0;
                
                game(socket);
            });
        }
    });
    socket.on('gameID', (data) => {
        MAIN.id = data;
    });
    socket.on('sendClientChat', (data) => {
        if(data.user == 'server'){
            $("#chat-list").append(`<li><span class="chat-message" style="color:rgba(255,255,255,0.8);"> ${data.msg}</span></li>`);
        }
        else {
            $("#chat-list").append(`<li><span class="chat-message"><span style="color:red;">${data.user}:</span> ${chatFilter(data.msg)}</span></li>`);
        }
        $("#chat-list").scrollTop($("#chat-list").prop('scrollHeight'));
    });
    socket.on('lobbyinfo', (data) => {
        MAP = data;
    });
    socket.on('refresh', (data) => {
        PLAYER_LIST = data.players;
        for(var P in PLAYER_LIST){
            if(MAIN.id == PLAYER_LIST[P].id){
                MAIN.position = PLAYER_LIST[P].position;
                break;
            }
        }
        $('#serverCPS').text(data.server.cps);
    });
}



var controlReady = {
    up:         true,
    down:       true,
    left:       true,
    right:      true,
    Q:          true,
    E:          true,
    R:          true,
    SHIFT:      true,
    SPACE:      true,
    ENTER:      true,
    click:      true
};
function controls(mobile, socket){  
    if(mobile){
        $('#touchable-screen').show();
        document.getElementById("touchable-screen").addEventListener("touchstart", function(event){
            event.preventDefault();
            event.stopImmediatePropagation();
            
            emitMouseClick(true);
            emitMouseAngle(socket, event.touches[0]);
        });
        document.getElementById("touchable-screen").addEventListener("touchmove", function(event){
            event.preventDefault();
            event.stopImmediatePropagation();
            
            emitMouseAngle(socket, event.touches[0]);
        });
        document.getElementById("touchable-screen").addEventListener("touchend", function(event){
            event.preventDefault();
            event.stopImmediatePropagation();
            
            emitMouseClick(false);
            emitMouseAngle(socket, event.touches[0]);
        });
        
        var joystickRadius  = Math.round(window.innerHeight/100 * 5);
        
        document.getElementById("joystick-left").style.width    = Math.round(window.innerHeight/100 * 30) +"px";
        document.getElementById("joystick-left").style.height   = Math.round(window.innerHeight/100 * 30) +"px";
        document.getElementById("joystick-left").style.left     = Math.round(window.innerHeight/100 * 3) +"px";
        document.getElementById("joystick-left").style.bottom   = Math.round(window.innerHeight/100 * 3) +"px";
        
        document.getElementById("joystick-left-stick").style.width  = Math.round(window.innerHeight/100 * 20) +"px";
        document.getElementById("joystick-left-stick").style.height     = Math.round(window.innerHeight/100 * 20) +"px";
        document.getElementById("joystick-left-stick").style.right  = Math.round(window.innerHeight/100 * 5) +"px";
        document.getElementById("joystick-left-stick").style.bottom     = Math.round(window.innerHeight/100 * 2.5) +"px";
        
        let myStickLeft = new JoystickController("joystick-left-stick", joystickRadius, 8);
        
        document.getElementById("joystick-right").style.width   = Math.round(window.innerHeight/100 * 30) +"px";
        document.getElementById("joystick-right").style.height  = Math.round(window.innerHeight/100 * 30) +"px";
        document.getElementById("joystick-right").style.right   = Math.round(window.innerHeight/100 * 3) +"px";
        document.getElementById("joystick-right").style.bottom  = Math.round(window.innerHeight/100 * 3) +"px";
        
        document.getElementById("joystick-right-stick").style.width     = Math.round(window.innerHeight/100 * 20) +"px";
        document.getElementById("joystick-right-stick").style.height    = Math.round(window.innerHeight/100 * 20) +"px";
        document.getElementById("joystick-right-stick").style.right     = Math.round(window.innerHeight/100 * 5) +"px";
        document.getElementById("joystick-right-stick").style.bottom    = Math.round(window.innerHeight/100 * 2.5) +"px";
        
        let myStickRight = new JoystickController("joystick-right-stick", joystickRadius, 8);
        
        $('#joystick-left').show();
        $('#joystick-right').show();
        $('#chat-input').hide();
    }
    else{
        document.addEventListener('mousemove', function(event){
            emitMouseAngle(socket, event);
        });
        document.addEventListener('mousedown', function(event){
            emitMouseAngle(socket, event);
            emitMouseClick(true);
        });
        document.addEventListener('mouseup', function(event){
            emitMouseAngle(socket, event);
            emitMouseClick(false);
        });
    }
    document.addEventListener('keydown', (event) => {
        if(controlReady.up && (event.keyCode === 87 || event.keyCode == 38)){//UP
            controlReady.up = false;
            socket.emit('controls',{inputId:'up',state:true});
        }
        if(controlReady.down && (event.keyCode == 83 || event.keyCode == 40)){//DOWN
            controlReady.down = false;
            socket.emit('controls',{inputId:'down',state:true});
        }
        if(controlReady.left && (event.keyCode == 65 || event.keyCode == 37)){//LEFT
            controlReady.left = false;
            socket.emit('controls',{inputId:'left',state:true});
        }
        if(controlReady.right && (event.keyCode == 68 || event.keyCode == 39)){//RIGHT
            controlReady.right = false;
            socket.emit('controls',{inputId:'right',state:true});
        }
        
        if(controlReady.Q && event.keyCode == 81){//Q
            controlReady.Q = false;
            socket.emit('controls',{inputId:'Q',state:true});
        }
        if(controlReady.E && event.keyCode == 69){//E
            controlReady.E = false;
            socket.emit('controls',{inputId:'E',state:true});
        }
        if(controlReady.R && event.keyCode == 82){//R
            controlReady.R = false;
            socket.emit('controls',{inputId:'R',state:true});
        }               
        if(controlReady.SHIFT && event.keyCode == 16){//SHIFT
            controlReady.SHIFT = false;
            socket.emit('controls',{inputId:'shift',state:true});
        }
        if(controlReady.SPACE && event.keyCode == 32){//SPACE
            controlReady.SPACE = false;
            socket.emit('controls',{inputId:'space',state:true});
        }
    });
    document.addEventListener('keyup', (event) => {
        if(!controlReady.up && (event.keyCode === 87 || event.keyCode == 38)){//UP
            controlReady.up = true;
            socket.emit('controls',{inputId:'up',state:false});
        }
        if(!controlReady.down && (event.keyCode == 83 || event.keyCode == 40)){//DOWN
            controlReady.down = true;
            socket.emit('controls',{inputId:'down',state:false});
        }
        if(!controlReady.left && (event.keyCode == 65 || event.keyCode == 37)){//LEFT
            controlReady.left = true;
            socket.emit('controls',{inputId:'left',state:false});
        }
        if(!controlReady.right && (event.keyCode == 68 || event.keyCode == 39)){//RIGHT
            controlReady.right = true;
            socket.emit('controls',{inputId:'right',state:false});
        }
        
        if(!controlReady.Q && event.keyCode == 81){//Q
            controlReady.Q = true;
            socket.emit('controls',{inputId:'Q',state:false});
        }
        if(!controlReady.E && event.keyCode == 69){//E
            controlReady.E = true;
            socket.emit('controls',{inputId:'E',state:false});
        }
        if(!controlReady.R && event.keyCode == 82){//R
            controlReady.R = true;
            socket.emit('controls',{inputId:'R',state:false});
        }               
        if(!controlReady.SHIFT && event.keyCode == 16){//false
            controlReady.SHIFT = true;
            socket.emit('controls',{inputId:'shift',state:false});
        }
        if(!controlReady.SPACE && event.keyCode == 32){//SPACE
            controlReady.SPACE = true;
            socket.emit('controls',{inputId:'space',state:false});
        }
    });
    
    
    $('#chat-input').focus(() => {
        controlReady.ENTER = false;
    });
    $('#chat-input').blur(() => {
        controlReady.ENTER = true;
    });
    function emitMouseAngle(socket, event) {
        var mouse;
        if(settings.mobile){
            mouse = {
                x: Math.round(event.clientX * pixelDensityRatio),
                y: Math.round(event.clientY * pixelDensityRatio)
            };
        }
        else {
            mouse = {
                x: Math.round(event.x * pixelDensityRatio),
                y: Math.round(event.y * pixelDensityRatio)
            };
        };
        var angle = Math.floor(Math.atan2(mouse.y - center.y, mouse.x - center.x) * 100)/100;
        socket.emit('angle', angle);
    }
    function emitMouseClick(click){
        if(click){
            socket.emit('controls',{inputId:'click',state:true});
        }
        else{
            socket.emit('controls',{inputId:'click',state:false});
        }
    }
}

带有 Redis 的 Node.js 服务器代码

const os            = require('os'),
      cluster       = require('cluster'),
      cores         = os.cpus();
var clusterCount = 0;

process.on('uncaughtException', function (exception) {
  console.log(exception); // to see your exception details in the console
  // if you are on production, maybe you can send the exception details to your
  // email as well ?
});

if(cluster.isMaster) {
    console.log(`Master ${process.pid} is running`);    
    // Fork workers
    for (let i = 0; i < cores.length; i++) {
        cluster.fork();
    }
    cluster.on('exit', (worker, code, signal) => {
        console.log(`worker ${worker.process.pid} died`);
    });
}
else{
    const http          = require('http'),
          express       = require('express'),
          socketio      = require('socket.io'),
          process       = require('process'),
          config        = require('./config.js'),
          socketioRedis = require('socket.io-redis'),
          redis         = require('./redis.js');
    
    const settings = {
        cps: 60
    };
    
    var LOBBY_LIST = {};
    
    redis.subscriber.on('connect', () => {
        console.log(`worker ${process.pid} connected to redis(subscriber)`);
        
        redis.subscriber.subscribe('LOBBIES');
        
        redis.subscriber.on('message', (channel, data) => {
            var parsedData = JSON.parse(data);
            switch(channel){
                case 'LOBBIES': {
                    //console.log(`Lobby -- ${parsedData.title} | ${parsedData.map} | ${parsedData.mode} | ${parsedData.max}`);
                    LOBBY_LIST[parsedData.title] = parsedData;
                    break;
                }
                default: {
                    break;
                }
            }
        });
        redis.subscriber.on('users', (channel, data) => {
            console.log(`${data.id} connected to worker ${data.server}`);
        });
    });
    redis.publisher.on('connect', () => {
        console.log(`worker ${process.pid} connected to redis(publisher)`);
        
        var cpu = cores[clusterCount];
        var app = express();
        var port = process.env.PORT || process.argv[2] || 8080;
        var server = app.listen(port);
        var io = socketio(server);
        var User = {};
        var SOCKET_LIST = {};
        var PLAYER_LIST = {};
        
        io.adapter(socketioRedis({host: config.redis_host, port: config.redis_port}));
        io.on('connection', (socket) => {
            User.onConnect(socket);
        });
        User.onConnect = (socket) => {
            console.log(`${socket.id} connected to worker ${process.pid}`);
            var id = socket.id;
            var player = new Player(id);
            
            SOCKET_LIST[id] = socket;
            SOCKET_LIST[id].spamGuard = 0;
            
            var updateLobbies = setInterval(() => {
                socket.emit('updateLobbies', LOBBY_LIST);
            }, 3000);
            
            socket.emit('gameID', id);
            
            socket.on('serverPing', (ping) => {
                socket.emit('serverPong', ping);
            });
            socket.on('sendServerChat', (data) => {
                if(data != ' ' && data != '  ' && data != '   '){
                    if(SOCKET_LIST[socket.id].spamGuard < 3){
                        if(data.length < 100){
                            var chat = {
                                user: socket.id,
                                msg: data
                            };
                            io.sockets.emit('sendClientChat', chat);
                            SOCKET_LIST[socket.id].spamGuard++;
                        }
                    }
                    else{
                        var chat = {
                            user: 'server',
                            msg: 'You\'re sending messages too fast!'
                        };
                        socket.emit('sendClientChat', chat);
                    }
                }
                else {
                    var chat = {
                        user: 'server',
                        msg: 'Can\'t send an empty message!'
                    };
                    socket.emit('sendClientChat', chat);
                }
            });
            socket.on('lobby.join', (lobby) => {
                var user = {
                    id: socket.id,
                    lobby: lobby
                };
                redis.publisher.publish('JOINROOM', JSON.stringify(user));
                
                socket.emit('lobbyinfo', map[LOBBY_LIST[lobby].map]);
            });
            socket.on('lobby.leave', () => {
                var user = {
                    id: socket.id,
                    lobby: lobby
                };
                redis.publisher.publish('LEAVEROOM', JSON.stringify(user));
            });
            socket.on('disconnect', () => {
                User.onDisconnect(socket);
            });
            socket.on('controls', (data) => {
                if(data.inputId === 'up'){//UP
                    player.controls.pressingUp = data.state;
                }
                else if(data.inputId === 'down'){//DOWN
                    player.controls.pressingDown = data.state;
                }
                else if(data.inputId === 'left'){//LEFT
                    player.controls.pressingLeft = data.state;
                }
                else if(data.inputId === 'right'){//RIGHT
                    player.controls.pressingRight = data.state;
                }
                else if(data.inputId === 'Q'){//Q
                    player.controls.pressingQ = data.state;
                }
                else if(data.inputId === 'E'){//E
                    player.controls.pressingE = data.state;
                }
                else if(data.inputId === 'R'){//R
                    player.controls.pressingR = data.state;
                }
                else if(data.inputId === 'shift'){//SHIFT
                    player.controls.pressingSHIFT = data.state;
                }
                else if(data.inputId === 'space'){//SPACE
                    player.controls.pressingSPACE = data.state;
                }
                
                if(data.inputId === 'click'){//Click
                    player.controls.leftClick = data.state;
                }
            });
            socket.on('angle', (data) => {
                player.angle = data;
            });
        };
        User.onDisconnect = (socket) => {
            console.log(`${socket.id} disconnected from worker ${process.pid}`);
            delete SOCKET_LIST[socket.id];
            delete PLAYER_LIST[socket.id];
            socket.disconnect();
        };
        
        var Player = function(id){
            var self = {
                id: id,
                username: 'player',
                server: '',
                position: {
                    x: 0,
                    y: 0
                },
                speed: 500,
                angle: degrees_to_radians(Math.floor(Math.random()*360)),
                controls: {
                    leftClick:      false,
                    pressingUp:     false,
                    pressingDown:   false,
                    pressingLeft:   false,
                    pressingRight:  false,
                    pressingQ:      false,
                    pressingE:      false,
                    pressingR:      false,
                    pressingSHIFT:  false,
                    pressingSPACE:  false
                }
            };
            self.updatePosition = function(){
                if(self.controls.pressingUp){
                    self.position.y -= self.speed / settings.cps;
                    if(self.position.y < 0){
                        self.position.y = 0;
                    }
                }
                if(self.controls.pressingDown){
                    self.position.y += self.speed / settings.cps;
                    if(self.position.y > 9999){
                        self.position.y = 9999;
                    }
                }
                if(self.controls.pressingLeft){
                    self.position.x -= self.speed / settings.cps;
                    if(self.position.x < 0){
                        self.position.x = 0;
                    }
                }
                if(self.controls.pressingRight){
                    self.position.x += self.speed / settings.cps;
                    if(self.position.x > 9999){
                        self.position.x = 9999;
                    }
                }
            };
            
            PLAYER_LIST[self.id] = self;
            return self;
        };
        Player.update = function(){     
            var pack = [];
            for(var i in PLAYER_LIST){
                var player = PLAYER_LIST[PLAYER_LIST[i].id];
                
                player.updatePosition();
                
                pack.push({
                    id: player.id,
                    position: player.position,
                    angle: player.angle
                });
            }
            return pack;
        };
        
        
        //Spam Guard
        setInterval(() => {
            for(var id in SOCKET_LIST){
                if(SOCKET_LIST[id].spamGuard > 0){
                    SOCKET_LIST[id].spamGuard--;
                }
            }
        }, 3000);
        //Update LOBBIES
        setInterval(() => {
            //for(var L in LOBBY_LIST){
            //  var lobby = LOBBY_LIST[L];
                checkCPS();
                
                var pack = {
                    players: Player.update(),
                    server: {
                        cps: cpsSave
                    }
                };
                
                for(var S in SOCKET_LIST){
                    var user = SOCKET_LIST[SOCKET_LIST[S].id];
                    
                    user.emit('refresh', pack);
                }
            //}
        }, 1000/settings.cps);
        
        var map = [
            'Urban Delight',
            'Graveyard',
            'Farmlands'
        ];
        for(var i in map){
            var mapName = map[i];
            
            map[mapName] = {
                tileSize: 100,
                matrix: [],
            };
            for(var j = 0; j < 100; j++){
                map[mapName].matrix[j] = [];
                for(var k = 0; k < 100; k++){
                    map[mapName].matrix[j][k] = 0;
                }
            }
        }       
        function degrees_to_radians(degrees){
            var pi = Math.PI;
            return degrees * (pi/180);
        }
        function radians_to_degrees(radians){
            var pi = Math.PI;
            return radians / (pi/180);
        }
        var cps = 0,
            cpsCheck = 0,
            cpsSave = 0;
        function checkCPS(){
            cps++;
            var d = new Date().getSeconds();
            if(cpsCheck != d){
                cpsCheck = d;
                cpsSave = cps;
                cps = 0;
            }
        }
        console.log(`Worker ${process.pid} started on port: ${port} | ${cpu.model}`);   
        clusterCount++;
    });
}

0 个答案:

没有答案
相关问题