Caio Keto
Caio Keto

Reputation: 2209

Socket.io not emitting more than 1 event

So I got an app in node.js to read CSGO demos, it parse the file, and I wanted to emit an event with socket.io to a client every time an entity is updated. It works, but it only fires "client.emit('tick', 'a');" but the console.log fires corretly, anyone can help me find out why socket.io is preventing the emit???

Server Code

var server = require('http').createServer();
var io = require('socket.io')(server);
var fs = require('fs');
var jsgo = require('jsgo');
io.on('connection', function(client){
    fs.readFile('train.dem', function (err, data) {
        var demo = new jsgo.Demo();
        demo.on('entity_updated', function (entity) {
            console.log('entity_updated');
            client.emit('tick', 'a');
        });
        demo.parse(data);
    });
});
server.listen(3000);

Client Code

var socket = io('http://localhost:3000');
socket.on('connect', function() {
    console.log('connected');
});
socket.on('tick', function (data) {
    console.log('entity_updated');
});
socket.on('disconnect', function() {
    console.log('disconnect');
});

Upvotes: 1

Views: 1770

Answers (2)

manishg
manishg

Reputation: 9818

I was able to reproduce this issue by using the file (train.dem) you provided. The reason why the socket.io is not able to send more than one message is due to this statement:

demo.parse(data);

node.js is a single threaded environment and the above statement is blocking the event loop. When I run the above statement, it is taking forever to complete. I ran the code for more than 15 minutes but this function didn't exit probably due to the amount of processing it's doing. Due to the event driven single thread environment, node is not able to send messages. All the messages are buffered and waiting for this loop to exit.

I added some more logs to your code and you can observe the writable flag:

socket.io:server initializing namespace / +0ms
  socket.io:server creating engine.io instance with opts {"path":"/socket.io"} +5ms
  socket.io:server attaching client serving req handler +4ms
  engine:socket sending packet "open" ({"sid":"SFD8FKG2G_MjW78SAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000}) +0ms
  engine:socket flushing buffer to transport +2ms
  engine:socket executing batch send callback +6ms
  socket.io:server incoming connection with id SFD8FKG2G_MjW78SAAAA +7s
  engine:socket sending packet "message" (0) +5ms
new client
  engine:socket might upgrade socket transport from "polling" to "websocket" +36ms
  engine:socket flushing buffer to transport +2ms
  engine:socket executing batch send callback +5ms
  engine:ws received "2probe" +15ms
  engine:ws writing "3probe" +2ms
readFile done null
started
server --> entity_updated for 1client.conn.transport.writable true
  engine:socket sending packet "message" (2["tick","a"]) +258ms
  engine:socket flushing buffer to transport +1ms
server --> entity_updated for 2client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +2ms
server --> entity_updated for 3client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +1ms
server --> entity_updated for 4client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 5client.conn.transport.writable false

The same can be reproduce using a for..loop. Check the code below:

 for (i=0; i<10; i++)
 {
     console.log('server --> entity_updated for ' + count + 'client.conn.transport.writable ' + client.conn.transport.writable);
     count++;
     client.emit('tick', 'a');  
 }

and the log below:

 socket.io:server initializing namespace / +0ms
  socket.io:server creating engine.io instance with opts {"path":"/socket.io"} +7ms
  socket.io:server attaching client serving req handler +3ms
  engine:socket sending packet "open" ({"sid":"b86YJD0sGGawVZseAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000}) +0ms
  engine:socket flushing buffer to transport +2ms
  engine:socket executing batch send callback +6ms
  socket.io:server incoming connection with id b86YJD0sGGawVZseAAAA +2s
  engine:socket sending packet "message" (0) +6ms
new client
  engine:socket might upgrade socket transport from "polling" to "websocket" +23ms
  engine:socket flushing buffer to transport +4ms
  engine:socket executing batch send callback +2ms
  engine:ws received "2probe" +8ms
  engine:ws writing "3probe" +5ms
readFile done null
started
ended
server --> entity_updated for 1client.conn.transport.writable true
server --> entity_updated for 1client.conn.transport.writable true
  engine:socket sending packet "message" (2["tick","a"]) +100ms
  engine:socket flushing buffer to transport +0ms
server --> entity_updated for 2client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +1ms
server --> entity_updated for 3client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 4client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 5client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 6client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +1ms
server --> entity_updated for 7client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 8client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 9client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +0ms
server --> entity_updated for 10client.conn.transport.writable false
  engine:socket sending packet "message" (2["tick","a"]) +0ms
  engine:ws received "5" +3ms
  engine:socket got upgrade packet - upgrading +0ms
  engine:socket flushing buffer to transport +1ms
  engine:ws writing "42["tick","a"]" +0ms
  engine:ws writing "42["tick","a"]" +1ms
  engine:ws writing "42["tick","a"]" +0ms
  engine:ws writing "42["tick","a"]" +0ms
  engine:ws writing "42["tick","a"]" +0ms
  engine:ws writing "42["tick","a"]" +0ms
  engine:ws writing "42["tick","a"]" +0ms
  engine:ws writing "42["tick","a"]" +1ms
  engine:ws writing "42["tick","a"]" +1ms
  engine:socket executing batch send callback +0ms

Once the for loop ends, the socket/io layer writes the data over socket. The same will happen to your code once demo.parse() completes processing.

You will have to figure out an alternate way of getting the data from jsgo in order to unblock the event loop and feeding the same to socket.io. Probably you can raise an enhancement request on jsgo github.

Upvotes: 1

Asif Saeed
Asif Saeed

Reputation: 2045

You have to save socket in some storage to emit every time enitity is updated.

for now you can try saving socket when connected in a variable but this wont work for many client because each time new socket is connected variable will be updated with new socket id.

    var server = require('http').createServer();
    var io = require('socket.io')(server);
    var fs = require('fs');
    var jsgo = require('jsgo');
    var socketId;  // this will only store one id. store it in some data storage or create room for each user and emit in room
    io.on('connection', function(client){
        socketId = client.id;
        fs.readFile('train.dem', function (err, data) {
            var demo = new jsgo.Demo();
            demo.on('entity_updated', function (entity) {
                console.log('entity_updated');
                if(io.sockets.connected[socketId]) //check if socket is still connected.
                {
                    io.sockets.to(socket.socketId).emit('tick', 'a');
                }

            });
            demo.parse(data);
        });
    });
    server.listen(3000);

Upvotes: 0

Related Questions